Compare commits
34 Commits
feature/as
...
feature/cl
| Author | SHA1 | Date | |
|---|---|---|---|
| 5ee9293daf | |||
| 89cd2a9d37 | |||
| ce0fde18dc | |||
| acf9fa348e | |||
| 74dd65efde | |||
| edc5ba9822 | |||
| 8902718523 | |||
| 1c4f03ea83 | |||
| 627904abba | |||
| bd3f53b596 | |||
| 69919878fa | |||
| f3bdf12bc4 | |||
| eb1211cde7 | |||
|
|
b8ed27f2ff | ||
| 74cfcfa16b | |||
| 9f95e89a9a | |||
| 5cd23ff343 | |||
| 615330bb46 | |||
| bcf6662db6 | |||
| be43f8a4a4 | |||
| c3a78f8a40 | |||
| 6c6a7c3919 | |||
| 63c53d18d1 | |||
| a5db01bd25 | |||
| 5d4033a9ca | |||
| 27523b8cce | |||
| f6117743ad | |||
| 8c97df9fc4 | |||
| 4f2bb19d8a | |||
| 13764a3766 | |||
| ed273fdafa | |||
| d706bf0623 | |||
| 13542cd3c0 | |||
|
|
a7e688a52c |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -12,3 +12,6 @@ npm-debug.log
|
||||
yarn-error.log
|
||||
/.idea
|
||||
/.vscode
|
||||
|
||||
/public/dashboard
|
||||
/public/dashboard-staging
|
||||
|
||||
0
Modules/HospitalPortal/Config/.gitkeep
Normal file
0
Modules/HospitalPortal/Config/.gitkeep
Normal file
5
Modules/HospitalPortal/Config/config.php
Normal file
5
Modules/HospitalPortal/Config/config.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'HospitalPortal'
|
||||
];
|
||||
0
Modules/HospitalPortal/Console/.gitkeep
Normal file
0
Modules/HospitalPortal/Console/.gitkeep
Normal file
0
Modules/HospitalPortal/Database/Migrations/.gitkeep
Normal file
0
Modules/HospitalPortal/Database/Migrations/.gitkeep
Normal file
0
Modules/HospitalPortal/Database/Seeders/.gitkeep
Normal file
0
Modules/HospitalPortal/Database/Seeders/.gitkeep
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\HospitalPortal\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class HospitalPortalDatabaseSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
Model::unguard();
|
||||
|
||||
// $this->call("OthersTableSeeder");
|
||||
}
|
||||
}
|
||||
0
Modules/HospitalPortal/Database/factories/.gitkeep
Normal file
0
Modules/HospitalPortal/Database/factories/.gitkeep
Normal file
0
Modules/HospitalPortal/Entities/.gitkeep
Normal file
0
Modules/HospitalPortal/Entities/.gitkeep
Normal file
0
Modules/HospitalPortal/Http/Controllers/.gitkeep
Normal file
0
Modules/HospitalPortal/Http/Controllers/.gitkeep
Normal file
128
Modules/HospitalPortal/Http/Controllers/Api/AuthController.php
Executable file
128
Modules/HospitalPortal/Http/Controllers/Api/AuthController.php
Executable file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\HospitalPortal\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Crypt;
|
||||
use Error;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Modules\Internal\Emails\SendVerifyEmail;
|
||||
use Modules\Internal\Events\ForgetPassword;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
public function login(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email',
|
||||
'password' => 'required'
|
||||
]);
|
||||
|
||||
$user = User::query()
|
||||
->where('email', $request->email)
|
||||
->first();
|
||||
|
||||
if (!$user) {
|
||||
return response(['message' => 'User Tidak Ditemukan'], 404);
|
||||
}
|
||||
|
||||
if (!Hash::check($request->password, $user->password)) {
|
||||
return response(['message' => 'Password Salah'], 403);
|
||||
}
|
||||
|
||||
return response([
|
||||
'message' => 'Selamat Datang',
|
||||
'user' => $user,
|
||||
'token' => $user->createToken('app')->plainTextToken
|
||||
]);
|
||||
}
|
||||
|
||||
public function logout(Request $request)
|
||||
{
|
||||
$token = $request->bearerToken();
|
||||
Auth::user()->tokens()->where('id', $token)->delete();
|
||||
|
||||
return response(['message' => 'Berhasil Logout.']);
|
||||
}
|
||||
|
||||
public function resetPassword(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
$request->validate([
|
||||
'old_password' => 'required',
|
||||
'new_password' => 'required',
|
||||
'confirm_new_password' => 'required'
|
||||
]);
|
||||
|
||||
if (!Hash::check($request['old_password'], $user->password)) {
|
||||
return response(['message' => 'Password Salah'], 403);
|
||||
}
|
||||
|
||||
if ($request["new_password"] != $request["confirm_new_password"]) {
|
||||
return response([
|
||||
'message' => "Password Tidak Sama"
|
||||
]);
|
||||
}
|
||||
|
||||
$user->update([
|
||||
'password' => Hash::make($request->confirm_new_password),
|
||||
]);
|
||||
return response()->json($user);
|
||||
}
|
||||
|
||||
public function verifyEmail(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email',
|
||||
]);
|
||||
|
||||
$user = User::query()
|
||||
->where('email', $request->email)
|
||||
->first();
|
||||
|
||||
if (!$user) {
|
||||
return response(['message' => 'User Tidak Ditemukan'], 404);
|
||||
}
|
||||
|
||||
Event(new ForgetPassword($user));
|
||||
|
||||
// Mail::to($user->email)->send(new SendVerifyEmail($user));
|
||||
|
||||
return response()->json($user);
|
||||
}
|
||||
|
||||
public function forgetPassword(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'new_password' => 'required',
|
||||
'confirm_new_password' => 'required'
|
||||
]);
|
||||
|
||||
$token = Crypt::decryptString($request->token);
|
||||
$email = explode('|', $token)[0];
|
||||
|
||||
$user = User::query()
|
||||
->where('email', $email)
|
||||
->first();
|
||||
|
||||
if (!$user) {
|
||||
return response(['message' => 'User Tidak Ditemukan'], 404);
|
||||
}
|
||||
|
||||
if ($request["new_password"] != $request["confirm_new_password"]) {
|
||||
return response([
|
||||
'message' => "Password Tidak Sama"
|
||||
], 404);
|
||||
}
|
||||
|
||||
$user->update([
|
||||
'password' => Hash::make($request->confirm_new_password),
|
||||
]);
|
||||
return response()->json($user);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\HospitalPortal\Http\Controllers\Api;
|
||||
|
||||
use App\Events\ClaimRequested;
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\ClaimRequest;
|
||||
use App\Models\File;
|
||||
use App\Models\Member;
|
||||
use App\Services\ClaimRequestService;
|
||||
use App\Services\ClaimService;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Modules\HospitalPortal\Transformers\ClaimRequestResource;
|
||||
use Modules\HospitalPortal\Transformers\ClaimRequestShowResource;
|
||||
use PDF;
|
||||
|
||||
class ClaimRequestController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index(request $request)
|
||||
{
|
||||
$claimRequests = ClaimRequest::query()
|
||||
->when($request->search, function ($q, $search) {
|
||||
$q->where('code', 'LIKE', "%".$search."%");
|
||||
})
|
||||
->when($request->orderBy, function ($q, $orderBy) use ($request) {
|
||||
if (in_array($orderBy, ['submission_date', 'code'])) {
|
||||
$q->orderBy($orderBy, $request->order);
|
||||
}
|
||||
})
|
||||
->when($request->status, function($q, $status) {
|
||||
$q->where('status', $status);
|
||||
})
|
||||
->with(['member'])
|
||||
->orderBy('created_at', 'DESC')
|
||||
->paginate();
|
||||
|
||||
return Helper::responseJson($claimRequests);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('hospitalportal::create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
* @param Request $request
|
||||
* @return Renderable
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'member_id' => 'required',
|
||||
]);
|
||||
|
||||
$member = Member::find($request->member_id);
|
||||
$newClaimRequest = ClaimRequestService::storeClaimRequest(member: $member);
|
||||
|
||||
ClaimRequested::dispatch($newClaimRequest);
|
||||
|
||||
// Log History
|
||||
$newClaimRequest->histories()->create([
|
||||
'title' => 'New Claim Requested',
|
||||
'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})",
|
||||
'type' => 'info',
|
||||
'system_origin' => 'hospital-portal'
|
||||
]);
|
||||
|
||||
if ($request->hasFile('result_files')) {
|
||||
foreach ($request->result_files as $file) {
|
||||
$pathFile = File::storeFile('claim-result', $newClaimRequest->id, $file);
|
||||
$newClaimRequest->files()->updateOrCreate([
|
||||
'type' => 'claim-result',
|
||||
'name' => File::getFileName('claim-result', $newClaimRequest->id, $file),
|
||||
'original_name' => $file->getClientOriginalName(),
|
||||
'extension' => $file->getClientOriginalExtension(),
|
||||
'path' => $pathFile,
|
||||
'created_by' => auth()->user()->id,
|
||||
'updated_by' => auth()->user()->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->hasFile('diagnosa_files')) {
|
||||
foreach ($request->diagnosa_files as $file) {
|
||||
$pathFile = File::storeFile('claim-diagnosis', $newClaimRequest->id, $file);
|
||||
$newClaimRequest->files()->updateOrCreate([
|
||||
'type' => 'claim-diagnosis',
|
||||
'name' => File::getFileName('claim-diagnosis', $newClaimRequest->id, $file),
|
||||
'original_name' => $file->getClientOriginalName(),
|
||||
'extension' => $file->getClientOriginalExtension(),
|
||||
'path' => $pathFile,
|
||||
'created_by' => auth()->user()->id,
|
||||
'updated_by' => auth()->user()->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->hasFile('result_files')) {
|
||||
foreach ($request->result_files as $file) {
|
||||
$pathFile = File::storeFile('claim-kondisi', $newClaimRequest->id, $file);
|
||||
$newClaimRequest->files()->updateOrCreate([
|
||||
'type' => 'claim-kondisi',
|
||||
'name' => File::getFileName('claim-kondisi', $newClaimRequest->id, $file),
|
||||
'original_name' => $file->getClientOriginalName(),
|
||||
'extension' => $file->getClientOriginalExtension(),
|
||||
'path' => $pathFile,
|
||||
'created_by' => auth()->user()->id,
|
||||
'updated_by' => auth()->user()->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return Helper::responseJson(data: $request->toArray(), message: 'Claim Request berhasil ajukan!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
$claimRequest = ClaimRequest::findOrFail($id);
|
||||
$claimRequest->load([
|
||||
'histories' => function ($history) {
|
||||
$history->latest();
|
||||
}
|
||||
]);
|
||||
|
||||
return Helper::responseJson(data: ClaimRequestShowResource::make($claimRequest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return view('hospitalportal::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)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function generateLog($claim_request_id)
|
||||
{
|
||||
$claimRequest = ClaimRequest::findOrFail($claim_request_id);
|
||||
|
||||
if ($claimRequest->status != 'approved') {
|
||||
throw new Exception("Belum Teverifikasi", 1);
|
||||
}
|
||||
|
||||
$member = Member::findOrFail($claimRequest->member_id)
|
||||
->load(['currentPlan', 'currentPolicy', 'currentPlan.corporateBenefits', 'currentPlan.corporateBenefits.benefit']);
|
||||
|
||||
$pdf = PDF::loadView('pdf.guaranted_leter', compact('member', 'claimRequest'));
|
||||
return $pdf->download('Guaranted Letter - '.$member->full_name.'.pdf');
|
||||
|
||||
return $claimRequest;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\HospitalPortal\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Member;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
|
||||
class MemberController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function search(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'no_polis' => 'required',
|
||||
'birth_date' => 'required'
|
||||
]);
|
||||
|
||||
$member = Member::query()
|
||||
->where('member_id', $request->no_polis)
|
||||
->where('birth_date', $request->birth_date)
|
||||
->with(['person', 'currentCorporate',
|
||||
// 'currentCorporate.corporateServices' => function ($corporateService) {
|
||||
// $corporateService->where('status', 'active');
|
||||
// },
|
||||
// 'currentCorporate.corporateServices.service'
|
||||
// 'currentPlan.benefits',
|
||||
// 'currentPlan.corporateBenefit.plan',
|
||||
'currentPlan.corporateBenefits.benefit'
|
||||
])
|
||||
->firstOrFail();
|
||||
|
||||
|
||||
return Helper::responseJson($member);
|
||||
}
|
||||
}
|
||||
83
Modules/HospitalPortal/Http/Controllers/ClaimController.php
Normal file
83
Modules/HospitalPortal/Http/Controllers/ClaimController.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\HospitalPortal\Http\Controllers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Claim;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
|
||||
class ClaimController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$claims = Claim::where('deleted_at', 'ASD')->paginate(5);
|
||||
|
||||
return Helper::responseJson($claims);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('hospitalportal::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('hospitalportal::show');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return view('hospitalportal::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)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\HospitalPortal\Http\Controllers;
|
||||
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
|
||||
class HospitalPortalController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('hospitalportal::index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('hospitalportal::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('hospitalportal::show');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return view('hospitalportal::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)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
0
Modules/HospitalPortal/Http/Middleware/.gitkeep
Normal file
0
Modules/HospitalPortal/Http/Middleware/.gitkeep
Normal file
0
Modules/HospitalPortal/Http/Requests/.gitkeep
Normal file
0
Modules/HospitalPortal/Http/Requests/.gitkeep
Normal file
0
Modules/HospitalPortal/Providers/.gitkeep
Normal file
0
Modules/HospitalPortal/Providers/.gitkeep
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\HospitalPortal\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Database\Eloquent\Factory;
|
||||
|
||||
class HospitalPortalServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* @var string $moduleName
|
||||
*/
|
||||
protected $moduleName = 'HospitalPortal';
|
||||
|
||||
/**
|
||||
* @var string $moduleNameLower
|
||||
*/
|
||||
protected $moduleNameLower = 'hospitalportal';
|
||||
|
||||
/**
|
||||
* Boot the application events.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->registerTranslations();
|
||||
$this->registerConfig();
|
||||
$this->registerViews();
|
||||
$this->loadMigrationsFrom(module_path($this->moduleName, 'Database/Migrations'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register config.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerConfig()
|
||||
{
|
||||
$this->publishes([
|
||||
module_path($this->moduleName, 'Config/config.php') => config_path($this->moduleNameLower . '.php'),
|
||||
], 'config');
|
||||
$this->mergeConfigFrom(
|
||||
module_path($this->moduleName, 'Config/config.php'), $this->moduleNameLower
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register views.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerViews()
|
||||
{
|
||||
$viewPath = resource_path('views/modules/' . $this->moduleNameLower);
|
||||
|
||||
$sourcePath = module_path($this->moduleName, 'Resources/views');
|
||||
|
||||
$this->publishes([
|
||||
$sourcePath => $viewPath
|
||||
], ['views', $this->moduleNameLower . '-module-views']);
|
||||
|
||||
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register translations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerTranslations()
|
||||
{
|
||||
$langPath = resource_path('lang/modules/' . $this->moduleNameLower);
|
||||
|
||||
if (is_dir($langPath)) {
|
||||
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
|
||||
} else {
|
||||
$this->loadTranslationsFrom(module_path($this->moduleName, 'Resources/lang'), $this->moduleNameLower);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the services provided by the provider.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function provides()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
private function getPublishableViewPaths(): array
|
||||
{
|
||||
$paths = [];
|
||||
foreach (\Config::get('view.paths') as $path) {
|
||||
if (is_dir($path . '/modules/' . $this->moduleNameLower)) {
|
||||
$paths[] = $path . '/modules/' . $this->moduleNameLower;
|
||||
}
|
||||
}
|
||||
return $paths;
|
||||
}
|
||||
}
|
||||
69
Modules/HospitalPortal/Providers/RouteServiceProvider.php
Normal file
69
Modules/HospitalPortal/Providers/RouteServiceProvider.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\HospitalPortal\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
|
||||
class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* The module namespace to assume when generating URLs to actions.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $moduleNamespace = 'Modules\HospitalPortal\Http\Controllers';
|
||||
|
||||
/**
|
||||
* Called before routes are registered.
|
||||
*
|
||||
* Register any model bindings or pattern based filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
parent::boot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the routes for the application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function map()
|
||||
{
|
||||
$this->mapApiRoutes();
|
||||
|
||||
$this->mapWebRoutes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the "web" routes for the application.
|
||||
*
|
||||
* These routes all receive session state, CSRF protection, etc.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function mapWebRoutes()
|
||||
{
|
||||
Route::middleware('web')
|
||||
->namespace($this->moduleNamespace)
|
||||
->group(module_path('HospitalPortal', '/Routes/web.php'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the "api" routes for the application.
|
||||
*
|
||||
* These routes are typically stateless.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function mapApiRoutes()
|
||||
{
|
||||
Route::prefix('api')
|
||||
->middleware('api')
|
||||
->namespace($this->moduleNamespace)
|
||||
->group(module_path('HospitalPortal', '/Routes/api.php'));
|
||||
}
|
||||
}
|
||||
0
Modules/HospitalPortal/Resources/assets/.gitkeep
Normal file
0
Modules/HospitalPortal/Resources/assets/.gitkeep
Normal file
0
Modules/HospitalPortal/Resources/assets/js/app.js
Normal file
0
Modules/HospitalPortal/Resources/assets/js/app.js
Normal file
0
Modules/HospitalPortal/Resources/lang/.gitkeep
Normal file
0
Modules/HospitalPortal/Resources/lang/.gitkeep
Normal file
0
Modules/HospitalPortal/Resources/views/.gitkeep
Normal file
0
Modules/HospitalPortal/Resources/views/.gitkeep
Normal file
9
Modules/HospitalPortal/Resources/views/index.blade.php
Normal file
9
Modules/HospitalPortal/Resources/views/index.blade.php
Normal file
@@ -0,0 +1,9 @@
|
||||
@extends('hospitalportal::layouts.master')
|
||||
|
||||
@section('content')
|
||||
<h1>Hello World</h1>
|
||||
|
||||
<p>
|
||||
This view is loaded from module: {!! config('hospitalportal.name') !!}
|
||||
</p>
|
||||
@endsection
|
||||
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Module HospitalPortal</title>
|
||||
|
||||
{{-- Laravel Mix - CSS File --}}
|
||||
{{-- <link rel="stylesheet" href="{{ mix('css/hospitalportal.css') }}"> --}}
|
||||
|
||||
</head>
|
||||
<body>
|
||||
@yield('content')
|
||||
|
||||
{{-- Laravel Mix - JS File --}}
|
||||
{{-- <script src="{{ mix('js/hospitalportal.js') }}"></script> --}}
|
||||
</body>
|
||||
</html>
|
||||
0
Modules/HospitalPortal/Routes/.gitkeep
Normal file
0
Modules/HospitalPortal/Routes/.gitkeep
Normal file
44
Modules/HospitalPortal/Routes/api.php
Normal file
44
Modules/HospitalPortal/Routes/api.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\HospitalPortal\Http\Controllers\Api\AuthController;
|
||||
use Modules\HospitalPortal\Http\Controllers\Api\ClaimRequestController;
|
||||
use Modules\HospitalPortal\Http\Controllers\Api\MemberController;
|
||||
use Modules\HospitalPortal\Http\Controllers\ClaimController;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| API Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can register API routes for your application. These
|
||||
| routes are loaded by the RouteServiceProvider within a group which
|
||||
| is assigned the "api" middleware group. Enjoy building your API!
|
||||
|
|
||||
*/
|
||||
|
||||
Route::prefix('hospitalportal')->group(function () {
|
||||
|
||||
Route::post('login', [AuthController::class, 'login'])->name('login');
|
||||
Route::post('forget-password', [AuthController::class, 'forgetPassword'])->name('forget-password');
|
||||
Route::post('verify-email', [AuthController::class, 'verifyEmail'])->name('verify-email');
|
||||
|
||||
|
||||
Route::middleware('auth:sanctum')->group(function () {
|
||||
|
||||
Route::post('logout', [AuthController::class, 'logout'])->name('logout');
|
||||
Route::get('/user', function (Request $request) {
|
||||
return $request->user();
|
||||
});
|
||||
Route::put('reset-password', [AuthController::class, 'resetPassword'])->name('resetPassword');
|
||||
|
||||
Route::get('claims', [ClaimController::class, 'index']);
|
||||
|
||||
Route::post('search-member', [MemberController::class, 'search']);
|
||||
|
||||
Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index');
|
||||
Route::post('claim-requests', [ClaimRequestController::class, 'store'])->name('claim-requests.store');
|
||||
Route::get('claim-requests/{claim_request_id}/log', [ClaimRequestController::class, 'generateLog'])->name('claim-requests.generate-log');
|
||||
Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show');
|
||||
});
|
||||
});
|
||||
16
Modules/HospitalPortal/Routes/web.php
Normal file
16
Modules/HospitalPortal/Routes/web.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Web Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can register web routes for your application. These
|
||||
| routes are loaded by the RouteServiceProvider within a group which
|
||||
| contains the "web" middleware group. Now create something great!
|
||||
|
|
||||
*/
|
||||
|
||||
Route::prefix('hospitalportal')->group(function() {
|
||||
Route::get('/', 'HospitalPortalController@index');
|
||||
});
|
||||
0
Modules/HospitalPortal/Tests/Feature/.gitkeep
Normal file
0
Modules/HospitalPortal/Tests/Feature/.gitkeep
Normal file
0
Modules/HospitalPortal/Tests/Unit/.gitkeep
Normal file
0
Modules/HospitalPortal/Tests/Unit/.gitkeep
Normal file
31
Modules/HospitalPortal/Transformers/ClaimRequestResource.php
Normal file
31
Modules/HospitalPortal/Transformers/ClaimRequestResource.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\HospitalPortal\Transformers;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ClaimRequestResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
$data = parent::toArray($request);
|
||||
$historiesGroupByDate = $this->histories->mapToGroups(function($history) {
|
||||
return [$history->created_at->format('Y-m-d') => $history];
|
||||
});
|
||||
$data['histories_by_date'] = [];
|
||||
foreach ($historiesGroupByDate as $date => $histories) {
|
||||
$data['histories_by_date'][] = [
|
||||
'date' => $date,
|
||||
'histories' => $histories
|
||||
];
|
||||
}
|
||||
|
||||
return $data; //parent::toArray($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\HospitalPortal\Transformers;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ClaimRequestShowResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
$data = parent::toArray($request);
|
||||
$historiesGroupByDate = $this->histories->mapToGroups(function($history) {
|
||||
return [$history->created_at->format('Y-m-d') => $history];
|
||||
});
|
||||
$data['histories_by_date'] = [];
|
||||
foreach ($historiesGroupByDate as $date => $histories) {
|
||||
$data['histories_by_date'][] = [
|
||||
'date' => $date,
|
||||
'histories' => $histories
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
23
Modules/HospitalPortal/composer.json
Normal file
23
Modules/HospitalPortal/composer.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "nwidart/hospitalportal",
|
||||
"description": "",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Widart",
|
||||
"email": "n.widart@gmail.com"
|
||||
}
|
||||
],
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [],
|
||||
"aliases": {
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\HospitalPortal\\": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Modules/HospitalPortal/module.json
Normal file
13
Modules/HospitalPortal/module.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "HospitalPortal",
|
||||
"alias": "hospitalportal",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"priority": 0,
|
||||
"providers": [
|
||||
"Modules\\HospitalPortal\\Providers\\HospitalPortalServiceProvider"
|
||||
],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": []
|
||||
}
|
||||
21
Modules/HospitalPortal/package.json
Normal file
21
Modules/HospitalPortal/package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "npm run development",
|
||||
"development": "mix",
|
||||
"watch": "mix watch",
|
||||
"watch-poll": "mix watch -- --watch-options-poll=1000",
|
||||
"hot": "mix watch --hot",
|
||||
"prod": "npm run production",
|
||||
"production": "mix --production"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^0.21.4",
|
||||
"dotenv": "^10.0.0",
|
||||
"dotenv-expand": "^5.1.0",
|
||||
"laravel-mix": "^6.0.31",
|
||||
"laravel-mix-merge-manifest": "^2.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"postcss": "^8.3.7"
|
||||
}
|
||||
}
|
||||
14
Modules/HospitalPortal/webpack.mix.js
Normal file
14
Modules/HospitalPortal/webpack.mix.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const dotenvExpand = require('dotenv-expand');
|
||||
dotenvExpand(require('dotenv').config({ path: '../../.env'/*, debug: true*/}));
|
||||
|
||||
const mix = require('laravel-mix');
|
||||
require('laravel-mix-merge-manifest');
|
||||
|
||||
mix.setPublicPath('../../public').mergeManifest();
|
||||
|
||||
mix.js(__dirname + '/Resources/assets/js/app.js', 'js/hospitalportal.js')
|
||||
.sass( __dirname + '/Resources/assets/sass/app.scss', 'css/hospitalportal.css');
|
||||
|
||||
if (mix.inProduction()) {
|
||||
mix.version();
|
||||
}
|
||||
133
Modules/Internal/Http/Controllers/Api/ClaimRequestController.php
Normal file
133
Modules/Internal/Http/Controllers/Api/ClaimRequestController.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Internal\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\ClaimRequest;
|
||||
use App\Models\Member;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Knp\Snappy\Pdf;
|
||||
use Modules\Internal\Transformers\ClaimRequestResource;
|
||||
use Modules\Internal\Transformers\ClaimRequestShowResource;
|
||||
|
||||
class ClaimRequestController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$claimRequests = ClaimRequest::query()
|
||||
->when($request->search, function ($q, $search) {
|
||||
$q->where('code', 'LIKE', "%".$search."%");
|
||||
})
|
||||
->when($request->orderBy, function ($q, $orderBy) use ($request) {
|
||||
if (in_array($orderBy, ['submission_date', 'code'])) {
|
||||
$q->orderBy($orderBy, $request->order);
|
||||
}
|
||||
})
|
||||
->when(empty($request->orderBy), function ($q) {
|
||||
$q->orderBy('created_at', 'desc');
|
||||
})
|
||||
->when($request->status, function($q, $status) {
|
||||
$q->where('status', $status);
|
||||
})
|
||||
->with(['member', 'files'])
|
||||
->paginate();
|
||||
|
||||
return Helper::paginateResources(ClaimRequestResource::collection($claimRequests));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$claimRequest = ClaimRequest::findOrFail($id);
|
||||
$claimRequest->load([
|
||||
'histories' => function ($history) {
|
||||
$history->latest();
|
||||
},
|
||||
'files'
|
||||
]);
|
||||
|
||||
return Helper::responseJson(data: ClaimRequestShowResource::make($claimRequest));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function approve($id)
|
||||
{
|
||||
$claimRequest = ClaimRequest::findOrFail($id);
|
||||
$member = $claimRequest->member;
|
||||
|
||||
$claimRequest->status = 'approved';
|
||||
$claimRequest->save();
|
||||
|
||||
// Store Generated Documents
|
||||
$logContent = view('pdf.guaranted_leter', compact('member', 'claimRequest'));
|
||||
$claimRequest->generatedDocuments()->create([
|
||||
'type' => 'guarantee_letter',
|
||||
'title' => 'Guarantee Letter for '. $member->full_name,
|
||||
'document_type' => 'type',
|
||||
'html_content' => $logContent,
|
||||
'system_origin' => 'primecenter'
|
||||
]);
|
||||
|
||||
return $claimRequest;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ use App\Models\Member;
|
||||
use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
|
||||
use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
|
||||
use Box\Spout\Common\Entity\Row;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
@@ -42,10 +43,10 @@ class CorporateMemberController extends Controller
|
||||
'claims' => function ($claim) {
|
||||
// return $claim->whereBetween('requested_at', [now()->startOfYear(), now()->endOfYear()]);
|
||||
// return $claim->used(now()->startOfYear(), now()->endOfYear());
|
||||
}
|
||||
},
|
||||
'currentPlan',
|
||||
'currentPlan.benefits'
|
||||
])
|
||||
->with('currentPlan')
|
||||
// ->with
|
||||
->paginate()
|
||||
->appends($request->all());
|
||||
|
||||
@@ -231,7 +232,7 @@ class CorporateMemberController extends Controller
|
||||
}
|
||||
|
||||
|
||||
public function generateLog($member_id)
|
||||
public function generateLog(Request $request, $member_id)
|
||||
{
|
||||
$member = Member::findOrFail($member_id)
|
||||
->load([
|
||||
@@ -247,7 +248,7 @@ class CorporateMemberController extends Controller
|
||||
$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'));
|
||||
$pdf = PDF::loadView('pdf.guaranted_leter', compact(['member', 'dateOfAdmission']));
|
||||
return $pdf->download('Guaranted Letter - '.$member->full_name.'.pdf');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use Modules\Internal\Http\Controllers\Api\AppointmentController;
|
||||
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\ClaimRequestController;
|
||||
use Modules\Internal\Http\Controllers\Api\CorporateBenefitController;
|
||||
use Modules\Internal\Http\Controllers\Api\CorporateController;
|
||||
use Modules\Internal\Http\Controllers\Api\CorporateFormulariumController;
|
||||
@@ -130,8 +131,11 @@ Route::prefix('internal')->group(function () {
|
||||
|
||||
Route::resource('doctors', DoctorController::class);
|
||||
|
||||
|
||||
Route::get('generate-log/{member_id}', [CorporateMemberController::class, 'generateLog']);
|
||||
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::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show');
|
||||
});
|
||||
|
||||
Route::get('province', [ProvinceController::class, 'index']);
|
||||
|
||||
33
Modules/Internal/Transformers/ClaimRequestResource.php
Normal file
33
Modules/Internal/Transformers/ClaimRequestResource.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Internal\Transformers;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ClaimRequestResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
$filesGroupByType = $this->files->mapToGroups(function($file) {
|
||||
return [$file->type => $file];
|
||||
});
|
||||
|
||||
$data = [
|
||||
'id' => $this->id,
|
||||
'code' => $this->code,
|
||||
'submission_date' => $this->submission_date,
|
||||
'member' => $this->member,
|
||||
'status' => $this->status ?? 'unknown',
|
||||
'service_type' => $this->service_type,
|
||||
'files_by_type' => $filesGroupByType
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
40
Modules/Internal/Transformers/ClaimRequestShowResource.php
Normal file
40
Modules/Internal/Transformers/ClaimRequestShowResource.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Internal\Transformers;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ClaimRequestShowResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
$data = parent::toArray($request);
|
||||
|
||||
// Map Histories to Group by Dates
|
||||
$historiesGroupByDate = $this->histories->mapToGroups(function($history) {
|
||||
return [$history->created_at->format('Y-m-d') => $history];
|
||||
});
|
||||
$data['histories_by_date'] = [];
|
||||
foreach ($historiesGroupByDate as $date => $histories) {
|
||||
$data['histories_by_date'][] = [
|
||||
'date' => $date,
|
||||
'histories' => $histories
|
||||
];
|
||||
}
|
||||
|
||||
// Map Files by type
|
||||
$filesGroupByType = $this->files->mapToGroups(function($file) {
|
||||
return [Str::slug($file->type, '_') => $file];
|
||||
});
|
||||
$data['files_by_type'] = $filesGroupByType;
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\ClaimRequest;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
@@ -14,14 +15,16 @@ class ClaimRequested
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $claim_request;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct(ClaimRequest $claimRequest)
|
||||
{
|
||||
//
|
||||
$this->claim_request = $claimRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -256,6 +256,7 @@ class MembershipController extends Controller
|
||||
{
|
||||
$member = Member::where('member_id', $member_id)->firstOrFail();
|
||||
$member->load(['currentPlan', 'memberPlans']);
|
||||
$member->totalUsage = ClaimService::getMemberTotalUsage($member);
|
||||
|
||||
return Helper::responseJson(data: MemberResource::make($member));
|
||||
}
|
||||
|
||||
92
app/Http/Controllers/GeneratedDocumentController.php
Normal file
92
app/Http/Controllers/GeneratedDocumentController.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App;
|
||||
use App\Models\GeneratedDocument;
|
||||
use Illuminate\Http\Request;
|
||||
use PDF;
|
||||
use Response;
|
||||
|
||||
class GeneratedDocumentController extends Controller
|
||||
{
|
||||
// Display Content from generated_documents to used by pdf generator (wkhtmltopdf)
|
||||
public function show($id)
|
||||
{
|
||||
$document = GeneratedDocument::findOrFail($id);
|
||||
|
||||
return $document->html_content.$document->html_content.$document->html_content.$document->html_content.$document->html_content;
|
||||
}
|
||||
|
||||
public function header(Request $request)
|
||||
{
|
||||
return '<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<pre>'.json_encode($request->toArray()).'
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 200px; background-color: #00be67;"> asdkjasnd </td>
|
||||
<td style="width: 500px; background-color: #0a94e3;" align="center"> asjdkadsn </td>
|
||||
<td style="width: 200px; background-color: #7b3f25" align="right"> qkjwenkqwjenkqwjen </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>';
|
||||
}
|
||||
|
||||
public function footer()
|
||||
{
|
||||
return "<h2>Footer Fatherfucker</h2>";
|
||||
}
|
||||
|
||||
public function pdf($id)
|
||||
{
|
||||
// return 'fuck';
|
||||
// $document = GeneratedDocument::findOrFail($id);
|
||||
|
||||
// $pdf = PDF::loadFile('http://localhost:8000/');
|
||||
// $pdf = PDF::loadFile('http://aso-linksehat.local/');
|
||||
// return $pdf->inline();
|
||||
// dd(route('generated-document.show', $id));
|
||||
// $pdf = PDF::loadFile(route('generated-document.show', $id));
|
||||
// return $pdf->inline();
|
||||
|
||||
// $snappy = App::make('snappy.pdf');
|
||||
// $html = '<h1>Bill</h1><p>You owe me money, dude.</p>';
|
||||
// // $snappy->generateFromHtml($html, '/tmp/bill-123.pdf');
|
||||
// // $snappy->generate('http://www.github.com', '/tmp/github.pdf');
|
||||
// //Or output:
|
||||
// return new Response(
|
||||
// $snappy->getOutputFromHtml($html),
|
||||
// 200,
|
||||
// array(
|
||||
// 'Content-Type' => 'application/pdf',
|
||||
// 'Content-Disposition' => 'attachment; filename="file.pdf"'
|
||||
// )
|
||||
// );
|
||||
|
||||
$pdf = PDF::loadFile(route('generated-document.show', $id));
|
||||
|
||||
// $pdf->loadFile(route('generated-document.show', $id));
|
||||
// $pdf->loadFile(route('generated-document.show', $id));
|
||||
// $pdf->loadFile(route('generated-document.show', $id));
|
||||
// $pdf->loadFile(route('generated-document.show', $id));
|
||||
|
||||
// $pdf->setPaper('a4')->setOrientation('landscape')->setOption('margin-bottom', 0);
|
||||
|
||||
// $pdf->setOption('header-html', route('pdf.header'));
|
||||
// $pdf->setOption('footer-html', route('pdf.header'));
|
||||
// $pdf->setOption('footer-center', 'asdasdasd');
|
||||
|
||||
// $pdf->setOption('footer-html', route('pdf.footer'));
|
||||
// $pdf->loadHtml('asdasdasd');
|
||||
|
||||
return $pdf->inline();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Resources\OLDLMS;
|
||||
|
||||
use App\Services\ClaimService;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class MemberResource extends JsonResource
|
||||
@@ -27,16 +28,18 @@ class MemberResource extends JsonResource
|
||||
'plan' => $currentMemberPlan ? [
|
||||
'code' => $currentMemberPlan->plan->code ?? null,
|
||||
'start' => $currentMemberPlan->start,
|
||||
'end' => $currentMemberPlan->end
|
||||
'end' => $currentMemberPlan->end,
|
||||
'limit' => $this->currentPlan->limit_rules
|
||||
] : null,
|
||||
'policy_code' => $this->currentPolicy->code,
|
||||
'policy_code' => $this->currentPolicy?->code ?? null,
|
||||
'corporate' => [
|
||||
'code' => $this->currentPolicy->corporate->code,
|
||||
'name' => $this->currentPolicy->corporate->name,
|
||||
'welcome_message' => $this->currentPolicy->corporate->welcome_message,
|
||||
'help_text' => $this->currentPolicy->corporate->help_text,
|
||||
'avatar_url' => $this->currentpolicy->corporate->avatar_url
|
||||
]
|
||||
'code' => $this->currentPolicy?->corporate->code ?? null,
|
||||
'name' => $this->currentPolicy?->corporate->name,
|
||||
'welcome_message' => $this->currentPolicy?->corporate?->welcome_message,
|
||||
'help_text' => $this->currentPolicy?->corporate?->help_text,
|
||||
'avatar_url' => $this->currentpolicy?->corporate?->avatar_url
|
||||
],
|
||||
'limit_usage' => $this->totalUsage ?? null
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
|
||||
35
app/Listeners/NotifyClaimRequested.php
Normal file
35
app/Listeners/NotifyClaimRequested.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\ClaimRequested;
|
||||
use App\Models\User;
|
||||
use App\Notifications\ClaimRequestedNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class NotifyClaimRequested
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param \App\Events\ClaimRequested $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(ClaimRequested $event)
|
||||
{
|
||||
// TODO List Of User that should be notified about Claim that Requested
|
||||
$user = User::first();
|
||||
$user->notify(new ClaimRequestedNotification());
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,15 @@ class Benefit extends Model
|
||||
'active'
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"created_by",
|
||||
"updated_by",
|
||||
"deleted_by",
|
||||
];
|
||||
|
||||
public function scopeFilter($query, array $filters)
|
||||
{
|
||||
$query->when($filters['search'] ?? false, function ($query, $search) {
|
||||
|
||||
@@ -18,8 +18,11 @@ use Illuminate\Support\Str;
|
||||
class Claim extends Model
|
||||
{
|
||||
use HasFactory, Blameable, SoftDeletes;
|
||||
|
||||
protected static $code_prefix = 'CLM';
|
||||
|
||||
protected $fillable = [
|
||||
'claim_request_id',
|
||||
'code',
|
||||
'member_id',
|
||||
'total_claim',
|
||||
@@ -54,7 +57,8 @@ class Claim extends Model
|
||||
|
||||
static::creating(function ($model) {
|
||||
try {
|
||||
$model->code = (string) Str::orderedUuid(); // generate uuid
|
||||
$model->uuid = (string) Str::orderedUuid(); // generate uuid
|
||||
$model->code = self::getNextCode();
|
||||
} catch (\Exception $e) {
|
||||
abort(500, $e->getMessage());
|
||||
}
|
||||
@@ -78,9 +82,9 @@ class Claim extends Model
|
||||
'status' => $model->status
|
||||
]);
|
||||
|
||||
if ($model->status == 'requested') {
|
||||
ClaimRequested::dispatch($model);
|
||||
}
|
||||
// if ($model->status == 'requested') {
|
||||
// ClaimRequested::dispatch($model);
|
||||
// }
|
||||
|
||||
if ($model->status == 'received') {
|
||||
ClaimReceived::dispatch($model);
|
||||
@@ -104,6 +108,20 @@ class Claim extends Model
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static function getNextCode()
|
||||
{
|
||||
$last_number = self::withTrashed()->max('code');
|
||||
$next_number = empty($last_number) ? 1 : ((int) explode('-', $last_number)[1] + 1);
|
||||
|
||||
return self::makeCode($next_number);
|
||||
}
|
||||
|
||||
public static function makeCode($next_number)
|
||||
{
|
||||
return (string) self::$code_prefix .'-'. str_pad($next_number, 5, 0, STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
|
||||
public function files()
|
||||
{
|
||||
|
||||
48
app/Models/ClaimHistory.php
Normal file
48
app/Models/ClaimHistory.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Blameable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ClaimHistory extends Model
|
||||
{
|
||||
use HasFactory, Blameable;
|
||||
|
||||
public $fillable = [
|
||||
'claim_id',
|
||||
'title',
|
||||
'description',
|
||||
'type',
|
||||
'parent_id',
|
||||
'data',
|
||||
'system_origin'
|
||||
];
|
||||
|
||||
public static $types = [
|
||||
'info',
|
||||
'document-request',
|
||||
'document-submit'
|
||||
];
|
||||
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo(ClaimHistory::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function childs()
|
||||
{
|
||||
return $this->hasMany(Claimhistory::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function claim()
|
||||
{
|
||||
return $this->belongsTo(Claim::class, 'claim_id');
|
||||
}
|
||||
|
||||
public function historiable()
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
}
|
||||
143
app/Models/ClaimRequest.php
Normal file
143
app/Models/ClaimRequest.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Events\ClaimReceived;
|
||||
use App\Events\ClaimRequested;
|
||||
use App\Traits\Blameable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Str;
|
||||
|
||||
class ClaimRequest extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes, Blameable;
|
||||
|
||||
protected static $code_prefix = 'CRQ';
|
||||
|
||||
public $fillable = [
|
||||
'submission_date',
|
||||
'member_id',
|
||||
'status',
|
||||
'claim_id'
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
// 'created_at',
|
||||
'updated_at',
|
||||
'deleted_at',
|
||||
'created_by',
|
||||
'updated_by',
|
||||
'deleted_by',
|
||||
];
|
||||
|
||||
public static $status = [
|
||||
'draft' => 'Draft',
|
||||
'requested' => 'Requested',
|
||||
'received' => 'Received',
|
||||
'approved' => 'Approved',
|
||||
'postpone' => 'Postpone',
|
||||
'paid' => 'Paid',
|
||||
'declined' => 'Declined'
|
||||
];
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::creating(function ($model) {
|
||||
try {
|
||||
$model->uuid = (string) Str::orderedUuid(); // generate uuid
|
||||
$model->code = self::getNextCode();
|
||||
} catch (\Exception $e) {
|
||||
abort(500, $e->getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
static::created(function ($model) {
|
||||
// try {
|
||||
// if (!empty($model->status) && $model->status == 'requested') {
|
||||
// $model->histories()->create([
|
||||
// 'title' => 'New Claim Requested',
|
||||
// 'description' => "Claim Requested for Member : {$model->member->member_id} - ({$model->member->full_name})",
|
||||
// 'type' => 'info'
|
||||
// ]);
|
||||
// }
|
||||
// } catch (\Exception $e) {
|
||||
// abort(500, $e->getMessage());
|
||||
// }
|
||||
});
|
||||
|
||||
static::updated(function ($model) {
|
||||
if ($model->hasChanges(['status'])) {
|
||||
|
||||
// if ($model->status == 'requested') {
|
||||
// $model->histories()->create([
|
||||
// 'title' => 'New Claim Requested',
|
||||
// 'description' => "Claim Requested for Member : {$model->member->member_id} - ({$model->member->full_name})",
|
||||
// 'type' => 'info'
|
||||
// ]);
|
||||
// }
|
||||
|
||||
// if ($model->status == 'received') {
|
||||
// ClaimReceived::dispatch($model);
|
||||
// }
|
||||
|
||||
// if ($model->status == 'approved') {
|
||||
// ClaimApproved::dispatch($model);
|
||||
// }
|
||||
|
||||
// if ($model->status == 'postpone') {
|
||||
// ClaimPostpone::dispatch($model);
|
||||
// }
|
||||
|
||||
// if ($model->status == 'paid') {
|
||||
// ClaimPaid::dispatch($model);
|
||||
// }
|
||||
|
||||
// if ($model->status == 'declined') {
|
||||
// ClaimDeclined::dispatch($model);
|
||||
// }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static function getNextCode()
|
||||
{
|
||||
$last_number = self::withTrashed()->max('code');
|
||||
$next_number = empty($last_number) ? 1 : ((int) explode('-', $last_number)[1] + 1);
|
||||
|
||||
return self::makeCode($next_number);
|
||||
}
|
||||
|
||||
public static function makeCode($next_number)
|
||||
{
|
||||
return (string) self::$code_prefix .'-'. str_pad($next_number, 5, 0, STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
public function claims()
|
||||
{
|
||||
return $this->hasMany(Claim::class, 'claim_request_id');
|
||||
}
|
||||
|
||||
public function files()
|
||||
{
|
||||
return $this->morphMany(File::class, 'fileable');
|
||||
}
|
||||
|
||||
public function generatedDocuments()
|
||||
{
|
||||
return $this->morphMany(GeneratedDocument::class, 'generated_documentable');
|
||||
}
|
||||
|
||||
public function histories()
|
||||
{
|
||||
return $this->morphMany(ClaimHistory::class, 'historiable');
|
||||
}
|
||||
|
||||
public function member()
|
||||
{
|
||||
return $this->belongsTo(Member::class, 'member_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,20 @@ class File extends Model
|
||||
'fileable_id',
|
||||
'type',
|
||||
'name',
|
||||
'original_name',
|
||||
'extension',
|
||||
'path',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'deleted_at',
|
||||
'created_by',
|
||||
'updated_by',
|
||||
'deleted_by',
|
||||
];
|
||||
|
||||
public $appends = [
|
||||
'url'
|
||||
];
|
||||
@@ -27,7 +37,10 @@ class File extends Model
|
||||
public static $file_directories = [
|
||||
'import-temp' => 'import-temp/',
|
||||
'avatar' => 'user-avatar/',
|
||||
'dataDiri' => 'data-diri/'
|
||||
'dataDiri' => 'data-diri/',
|
||||
'claim-result' => 'claim/',
|
||||
'claim-diagnosis' => 'claim/',
|
||||
'claim-kondisi' => 'claim/',
|
||||
];
|
||||
|
||||
public function fileable()
|
||||
@@ -45,6 +58,11 @@ class File extends Model
|
||||
return $type . '-' . $id . '-' . Str::random(10);
|
||||
}
|
||||
|
||||
public function getNameAttribute($value)
|
||||
{
|
||||
return !empty($this->original_name) ? $this->original_name : ($value . '.' . $this->extension);
|
||||
}
|
||||
|
||||
public function getUrlAttribute()
|
||||
{
|
||||
return url(Storage::url($this->path));
|
||||
|
||||
41
app/Models/GeneratedDocument.php
Normal file
41
app/Models/GeneratedDocument.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use PDF;
|
||||
|
||||
class GeneratedDocument extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
public $fillable = [
|
||||
'type',
|
||||
'title',
|
||||
'document_type',
|
||||
'html_content',
|
||||
'system_origin',
|
||||
'parent_id'
|
||||
];
|
||||
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo(GeneratedDocument::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function childs()
|
||||
{
|
||||
return $this->hasMany(GeneratedDocument::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function generated_documentable()
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
public function makePdf()
|
||||
{
|
||||
return PDF::loadFile(route('generated-document.show', $this->id));
|
||||
}
|
||||
}
|
||||
@@ -193,12 +193,13 @@ class Member extends Model
|
||||
|
||||
public function getNameAttribute()
|
||||
{
|
||||
return $this->person->name ?? null;
|
||||
return $this->person->name ?? ($this->name ?? null);
|
||||
}
|
||||
|
||||
public function getBirthDateAttribute()
|
||||
{
|
||||
return Carbon::parse($this->person->birth_date ?? null)->format('Y-m-d') ?? null;
|
||||
$date = $this->person->birth_date ?? ($this->birth_date ?? null);
|
||||
return !empty($date) ? Carbon::parse($date)->format('Y-m-d') : null;
|
||||
}
|
||||
|
||||
public function getGenderAttribute()
|
||||
|
||||
27
app/Models/OLDLMS/Kota.php
Normal file
27
app/Models/OLDLMS/Kota.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\OLDLMS;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Kota extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
const CREATED_AT = 'dCreateOn';
|
||||
const UPDATED_AT = 'dUpdateOn';
|
||||
const DELETED_AT = 'dDeleteOn';
|
||||
|
||||
protected $connection = 'oldlms';
|
||||
|
||||
protected $table = 'tm_kota';
|
||||
|
||||
protected $primaryKey = 'nID';
|
||||
|
||||
public function provinsi()
|
||||
{
|
||||
return $this->belongsTo(Provinsi::class, 'nIDProvinsi', 'nID');
|
||||
}
|
||||
}
|
||||
22
app/Models/OLDLMS/Provinsi.php
Normal file
22
app/Models/OLDLMS/Provinsi.php
Normal 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 Provinsi extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
const CREATED_AT = 'dCreateOn';
|
||||
const UPDATED_AT = 'dUpdateOn';
|
||||
const DELETED_AT = 'dDeleteOn';
|
||||
|
||||
protected $connection = 'oldlms';
|
||||
|
||||
protected $table = 'tm_provinsi';
|
||||
|
||||
protected $primaryKey = 'nID';
|
||||
}
|
||||
@@ -182,7 +182,63 @@ class Plan extends Model
|
||||
return $this->belongsToMany(Benefit::class, 'corporate_benefits', 'plan_id', 'benefit_id')
|
||||
->withTimestamps()
|
||||
->withPivot([
|
||||
// TODO corporate_benefits pivot
|
||||
'corporate_id',
|
||||
'plan_id',
|
||||
'benefit_id',
|
||||
'corporate_benefit_code',
|
||||
'budget',
|
||||
'budget_conditions',
|
||||
'budget_code',
|
||||
'primary_benefit_code',
|
||||
'benefit_mode',
|
||||
'room_class_coverage',
|
||||
'max_bed_coverage',
|
||||
'tolerance_parameter',
|
||||
'max_room_class',
|
||||
'limit_amount',
|
||||
'area_limit',
|
||||
'shared_benefit',
|
||||
'shared_benefit_type',
|
||||
'msc',
|
||||
'genders',
|
||||
'min_age',
|
||||
'max_age',
|
||||
'max_frequency_period',
|
||||
'daily_frequency',
|
||||
'weekly_frequency',
|
||||
'monthly_frequency',
|
||||
'yearly_frequency',
|
||||
'custom_frequency_days',
|
||||
'custom_duration_value',
|
||||
'allowed_transaction_types',
|
||||
'high_plan_factor',
|
||||
'pre_post_treatment',
|
||||
'pre_treatment_days',
|
||||
'post_treatment_days',
|
||||
'layer_type_1',
|
||||
'layer_value_1',
|
||||
'layer_type_2',
|
||||
'layer_value_2',
|
||||
'cashless_percentage',
|
||||
'reimbursement_percentage',
|
||||
'digital_percentage',
|
||||
'co_share_m_percentage',
|
||||
'co_share_s_percentage',
|
||||
'co_share_c_percentage',
|
||||
'cashless_deductible',
|
||||
'reimbursement_deductible',
|
||||
'digital_deductible',
|
||||
'co_share_m_deductible',
|
||||
'co_share_s_deductible',
|
||||
'co_share_c_deductible',
|
||||
'prorate_type',
|
||||
'prorate_lookup',
|
||||
'max_days_for_disability',
|
||||
'max_period_for_disability',
|
||||
'currency',
|
||||
'show_benefit_item',
|
||||
'show_benefit_value',
|
||||
'active'
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -190,4 +246,9 @@ class Plan extends Model
|
||||
{
|
||||
return $this->hasMany(CorporateBenefit::class, 'plan_id', 'id');
|
||||
}
|
||||
|
||||
public function service()
|
||||
{
|
||||
return $this->belongsTo(Service::class, 'service_code', 'code');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,4 +14,9 @@ class Service extends Model
|
||||
'name',
|
||||
'description',
|
||||
];
|
||||
|
||||
public function corporateService()
|
||||
{
|
||||
return $this->hasMany(CorporateService::class, 'service_code', 'code');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,11 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens, HasFactory, Notifiable;
|
||||
use HasApiTokens, HasFactory, Notifiable, HasRoles;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
||||
61
app/Notifications/ClaimRequestedNotification.php
Normal file
61
app/Notifications/ClaimRequestedNotification.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class ClaimRequestedNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['database'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->line('The introduction to the notification.')
|
||||
->action('Notification Action', url('/'))
|
||||
->line('Thank you for using our application!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
'asdasd' => 'asdasdsd'
|
||||
];
|
||||
}
|
||||
}
|
||||
36
app/Providers/ClaimRequested.php
Normal file
36
app/Providers/ClaimRequested.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ClaimRequested
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return \Illuminate\Broadcasting\Channel|array
|
||||
*/
|
||||
public function broadcastOn()
|
||||
{
|
||||
return new PrivateChannel('channel-name');
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace App\Providers;
|
||||
|
||||
use App\Events\ClaimApproved;
|
||||
use App\Listeners\LogClaimJournal;
|
||||
use App\Listeners\NotifyClaimRequested;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
@@ -21,9 +22,14 @@ class EventServiceProvider extends ServiceProvider
|
||||
SendEmailVerificationNotification::class,
|
||||
],
|
||||
|
||||
ClaimRequested::class => [
|
||||
NotifyClaimRequested::class,
|
||||
],
|
||||
|
||||
ClaimApproved::class => [
|
||||
LogClaimJournal::class,
|
||||
]
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -43,6 +49,6 @@ class EventServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function shouldDiscoverEvents()
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
39
app/Services/ClaimRequestService.php
Normal file
39
app/Services/ClaimRequestService.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Events\ClaimApproved;
|
||||
use App\Events\ClaimRequested;
|
||||
use App\Models\Claim;
|
||||
use App\Models\ClaimRequest;
|
||||
use App\Models\Icd;
|
||||
use App\Models\Member;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Str;
|
||||
|
||||
class ClaimRequestService{
|
||||
|
||||
public static function storeClaimRequest($member, $submissionDate = null, $status = 'requested')
|
||||
{
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
$claimRequestData = [
|
||||
'member_id' => $member->id,
|
||||
'submission_date' => $submissionDate ?? now(),
|
||||
'status' => $status
|
||||
];
|
||||
|
||||
$claimRequest = ClaimRequest::create($claimRequestData);
|
||||
|
||||
DB::commit();
|
||||
return $claimRequest;
|
||||
} catch (\Exception $error) {
|
||||
DB::rollBack();
|
||||
|
||||
throw new \Exception($error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -119,8 +119,6 @@ class ClaimService{
|
||||
->active()
|
||||
->first();
|
||||
|
||||
// dd($benefit->toArray());
|
||||
// dd(compact(['plan', 'policy', 'corporate', 'benefit']));
|
||||
$limits = [
|
||||
'total_limit' => $corporateBenefit ? $corporateBenefit->limit_amount : 0,
|
||||
'frequency_limit_name' => $corporateBenefit ? $corporateBenefit->max_frequency_period_name : null,
|
||||
@@ -163,22 +161,21 @@ class ClaimService{
|
||||
return $limits;
|
||||
}
|
||||
|
||||
public static function storeClaim($member, $diagnosis, $totalClaim, $benefit, $status)
|
||||
public static function storeClaim($member, $diagnosis = null, $totalClaim = null, $benefit = null, $status = 'requested', $claimRequest = null)
|
||||
{
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
$claimData = [
|
||||
'member_id' => $member->id,
|
||||
'claim_request_id' => $claimRequest->id ?? null,
|
||||
'diagnosis_id' => $diagnosis->id ?? null,
|
||||
'total_claim' => $totalClaim,
|
||||
'total_claim' => $totalClaim ?? null,
|
||||
'currency' => 'IDR',
|
||||
'plan_id' => $member->currentPlan->id,
|
||||
'benefit_id' => $benefit->id,
|
||||
'plan_id' => $member->currentPlan->id ?? null,
|
||||
'benefit_id' => $benefit->id ?? null,
|
||||
'status' => $status
|
||||
];
|
||||
// $claimData[$status.'_at'] = now();
|
||||
// $claimData[$status.'_by'] = auth()->user()->id ?? null;
|
||||
|
||||
$claim = Claim::create($claimData);
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"maatwebsite/excel": "^3.1",
|
||||
"nwidart/laravel-modules": "^9.0",
|
||||
"psr/simple-cache": "^1.0",
|
||||
"pusher/pusher-php-server": "^7.2"
|
||||
"pusher/pusher-php-server": "^7.2",
|
||||
"spatie/laravel-permission": "^5.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.7",
|
||||
|
||||
1092
composer.lock
generated
Executable file → Normal file
1092
composer.lock
generated
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
@@ -188,6 +188,7 @@ return [
|
||||
Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
|
||||
Maatwebsite\Excel\ExcelServiceProvider::class,
|
||||
Barryvdh\Snappy\ServiceProvider::class,
|
||||
Spatie\Permission\PermissionServiceProvider::class,
|
||||
|
||||
/*
|
||||
* Application Service Providers...
|
||||
|
||||
161
config/permission.php
Normal file
161
config/permission.php
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'models' => [
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your permissions. Of course, it
|
||||
* is often just the "Permission" model but you may use whatever you like.
|
||||
*
|
||||
* The model you want to use as a Permission model needs to implement the
|
||||
* `Spatie\Permission\Contracts\Permission` contract.
|
||||
*/
|
||||
|
||||
'permission' => Spatie\Permission\Models\Permission::class,
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your roles. Of course, it
|
||||
* is often just the "Role" model but you may use whatever you like.
|
||||
*
|
||||
* The model you want to use as a Role model needs to implement the
|
||||
* `Spatie\Permission\Contracts\Role` contract.
|
||||
*/
|
||||
|
||||
'role' => Spatie\Permission\Models\Role::class,
|
||||
|
||||
],
|
||||
|
||||
'table_names' => [
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your roles. We have chosen a basic
|
||||
* default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'roles' => 'roles',
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* table should be used to retrieve your permissions. We have chosen a basic
|
||||
* default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'permissions' => 'permissions',
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* table should be used to retrieve your models permissions. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'model_has_permissions' => 'model_has_permissions',
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your models roles. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'model_has_roles' => 'model_has_roles',
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your roles permissions. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'role_has_permissions' => 'role_has_permissions',
|
||||
],
|
||||
|
||||
'column_names' => [
|
||||
/*
|
||||
* Change this if you want to name the related pivots other than defaults
|
||||
*/
|
||||
'role_pivot_key' => null, //default 'role_id',
|
||||
'permission_pivot_key' => null, //default 'permission_id',
|
||||
|
||||
/*
|
||||
* Change this if you want to name the related model primary key other than
|
||||
* `model_id`.
|
||||
*
|
||||
* For example, this would be nice if your primary keys are all UUIDs. In
|
||||
* that case, name this `model_uuid`.
|
||||
*/
|
||||
|
||||
'model_morph_key' => 'model_id',
|
||||
|
||||
/*
|
||||
* Change this if you want to use the teams feature and your related model's
|
||||
* foreign key is other than `team_id`.
|
||||
*/
|
||||
|
||||
'team_foreign_key' => 'team_id',
|
||||
],
|
||||
|
||||
/*
|
||||
* When set to true, the method for checking permissions will be registered on the gate.
|
||||
* Set this to false, if you want to implement custom logic for checking permissions.
|
||||
*/
|
||||
|
||||
'register_permission_check_method' => true,
|
||||
|
||||
/*
|
||||
* When set to true the package implements teams using the 'team_foreign_key'. If you want
|
||||
* the migrations to register the 'team_foreign_key', you must set this to true
|
||||
* before doing the migration. If you already did the migration then you must make a new
|
||||
* migration to also add 'team_foreign_key' to 'roles', 'model_has_roles', and
|
||||
* 'model_has_permissions'(view the latest version of package's migration file)
|
||||
*/
|
||||
|
||||
'teams' => false,
|
||||
|
||||
/*
|
||||
* When set to true, the required permission names are added to the exception
|
||||
* message. This could be considered an information leak in some contexts, so
|
||||
* the default setting is false here for optimum safety.
|
||||
*/
|
||||
|
||||
'display_permission_in_exception' => false,
|
||||
|
||||
/*
|
||||
* When set to true, the required role names are added to the exception
|
||||
* message. This could be considered an information leak in some contexts, so
|
||||
* the default setting is false here for optimum safety.
|
||||
*/
|
||||
|
||||
'display_role_in_exception' => false,
|
||||
|
||||
/*
|
||||
* By default wildcard permission lookups are disabled.
|
||||
*/
|
||||
|
||||
'enable_wildcard_permission' => false,
|
||||
|
||||
'cache' => [
|
||||
|
||||
/*
|
||||
* By default all permissions are cached for 24 hours to speed up performance.
|
||||
* When permissions or roles are updated the cache is flushed automatically.
|
||||
*/
|
||||
|
||||
'expiration_time' => \DateInterval::createFromDateString('24 hours'),
|
||||
|
||||
/*
|
||||
* The cache key used to store all permissions.
|
||||
*/
|
||||
|
||||
'key' => 'spatie.permission.cache',
|
||||
|
||||
/*
|
||||
* You may optionally indicate a specific cache driver to use for permission and
|
||||
* role caching using any of the `store` drivers listed in the cache.php config
|
||||
* file. Using 'default' here means to use the `default` set in cache.php.
|
||||
*/
|
||||
|
||||
'store' => 'default',
|
||||
],
|
||||
];
|
||||
@@ -15,7 +15,9 @@ return new class extends Migration
|
||||
{
|
||||
Schema::create('claims', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid');
|
||||
$table->string('code')->index();
|
||||
$table->foreignId('claim_request_id')->nullable()->index();
|
||||
$table->foreignId('member_id')->index();
|
||||
// $table->foreignId('diagnosis_id')->index()->nullable();
|
||||
$table->string('currency');
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('claim_requests', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid');
|
||||
$table->string('code')->index();
|
||||
$table->dateTime('submission_date')->nullable();
|
||||
$table->foreignId('member_id');
|
||||
$table->string('status')->nullable();
|
||||
$table->foreignId('claim_id')->nullable()->comment('After Claim is Created');
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
$table->unsignedBigInteger('created_by')->nullable()->index();
|
||||
$table->unsignedBigInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedBigInteger('deleted_by')->nullable()->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('claim_requests');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Spatie\Permission\PermissionRegistrar;
|
||||
|
||||
class CreatePermissionTables extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
$columnNames = config('permission.column_names');
|
||||
$teams = config('permission.teams');
|
||||
|
||||
if (empty($tableNames)) {
|
||||
throw new \Exception('Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
}
|
||||
if ($teams && empty($columnNames['team_foreign_key'] ?? null)) {
|
||||
throw new \Exception('Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
}
|
||||
|
||||
Schema::create($tableNames['permissions'], function (Blueprint $table) {
|
||||
$table->bigIncrements('id'); // permission id
|
||||
$table->string('name'); // For MySQL 8.0 use string('name', 125);
|
||||
$table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['name', 'guard_name']);
|
||||
});
|
||||
|
||||
Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) {
|
||||
$table->bigIncrements('id'); // role id
|
||||
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
|
||||
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
|
||||
}
|
||||
$table->string('name'); // For MySQL 8.0 use string('name', 125);
|
||||
$table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125);
|
||||
$table->timestamps();
|
||||
if ($teams || config('permission.testing')) {
|
||||
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
|
||||
} else {
|
||||
$table->unique(['name', 'guard_name']);
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) {
|
||||
$table->unsignedBigInteger(PermissionRegistrar::$pivotPermission);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
|
||||
|
||||
$table->foreign(PermissionRegistrar::$pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
} else {
|
||||
$table->primary([PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) {
|
||||
$table->unsignedBigInteger(PermissionRegistrar::$pivotRole);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
|
||||
|
||||
$table->foreign(PermissionRegistrar::$pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
} else {
|
||||
$table->primary([PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames) {
|
||||
$table->unsignedBigInteger(PermissionRegistrar::$pivotPermission);
|
||||
$table->unsignedBigInteger(PermissionRegistrar::$pivotRole);
|
||||
|
||||
$table->foreign(PermissionRegistrar::$pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->foreign(PermissionRegistrar::$pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->primary([PermissionRegistrar::$pivotPermission, PermissionRegistrar::$pivotRole], 'role_has_permissions_permission_id_role_id_primary');
|
||||
});
|
||||
|
||||
app('cache')
|
||||
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
|
||||
->forget(config('permission.cache.key'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
|
||||
if (empty($tableNames)) {
|
||||
throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
|
||||
}
|
||||
|
||||
Schema::drop($tableNames['role_has_permissions']);
|
||||
Schema::drop($tableNames['model_has_roles']);
|
||||
Schema::drop($tableNames['model_has_permissions']);
|
||||
Schema::drop($tableNames['roles']);
|
||||
Schema::drop($tableNames['permissions']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('files', function (Blueprint $table) {
|
||||
$table->string('original_name')->nullable()->after('name');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('files', function (Blueprint $table) {
|
||||
$table->dropColumn('original_name');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('claim_histories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->morphs('historiable');
|
||||
$table->string('title')->nullable();
|
||||
$table->string('description')->nullable();
|
||||
$table->string('type');
|
||||
$table->foreignId('parent_id')->nullable();
|
||||
$table->text('data')->nullable();
|
||||
$table->string('system_origin')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
$table->unsignedBigInteger('created_by')->nullable()->index();
|
||||
$table->unsignedBigInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedBigInteger('deleted_by')->nullable()->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('claim_histories');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('generated_documents', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->morphs('generated_documentable', 'generated_document_index');
|
||||
$table->string('type');
|
||||
$table->string('title');
|
||||
$table->string('document_type')->nullable();
|
||||
$table->string('system_origin');
|
||||
$table->text('html_content')->nullable();
|
||||
$table->text('data')->nullable();
|
||||
$table->foreignId('parent_id')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
$table->unsignedBigInteger('created_by')->nullable()->index();
|
||||
$table->unsignedBigInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedBigInteger('deleted_by')->nullable()->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('generated_documents');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('notifications', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->string('type');
|
||||
$table->morphs('notifiable');
|
||||
$table->text('data');
|
||||
$table->timestamp('read_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('notifications');
|
||||
}
|
||||
};
|
||||
@@ -17,18 +17,23 @@ class DummyMemberSeeder extends Seeder
|
||||
public function run()
|
||||
{
|
||||
$userEmails = [
|
||||
'admin@linksehat.dev',
|
||||
'manager+one@gmail.com',
|
||||
'manager+two@gmail.com'
|
||||
'admin@linksehat.dev' => ['administrator'],
|
||||
'manager+one@gmail.com' => ['corporate-manager'],
|
||||
'manager+two@gmail.com' => ['corporate-manager'],
|
||||
'hospitaladmin@gmail.com' => ['hospital-admin']
|
||||
];
|
||||
|
||||
foreach ($userEmails as $email) {
|
||||
User::updateOrCreate([
|
||||
foreach ($userEmails as $email => $roles) {
|
||||
$user = User::updateOrCreate([
|
||||
'email' => $email
|
||||
], [
|
||||
'email' => $email,
|
||||
'password' => Hash::make('password')
|
||||
]);
|
||||
|
||||
if (isset($roles) && count($roles)) {
|
||||
$user->syncRoles($roles);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
85
database/seeders/IngestProviderSeeder.php
Normal file
85
database/seeders/IngestProviderSeeder.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\OLDLMS\Healthcare;
|
||||
use App\Models\OLDLMS\Kota;
|
||||
use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Str;
|
||||
|
||||
class IngestProviderSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$file_path = resource_path('files/providers.csv');
|
||||
$reader = ReaderEntityFactory::createReaderFromFile($file_path);
|
||||
$reader->open($file_path);
|
||||
|
||||
$chunks = [];
|
||||
$time = now();
|
||||
foreach ($reader->getSheetIterator() as $sheet) {
|
||||
foreach ($sheet->getRowIterator() as $index => $row) {
|
||||
if ($index != 1) {
|
||||
$row_data = [
|
||||
'timezone' => 'Asia/Jakarta',
|
||||
'nIDType' => 2,
|
||||
'nIDCountry' => 1,
|
||||
'sMoto' => 'Memberikan Kesehatan Pelayanan Terbaik',
|
||||
'sStatus' => 1,
|
||||
'sCreateBy' => 9999999,
|
||||
];
|
||||
|
||||
$row_data['nIDHealthCareCategory'] = 1; // RS
|
||||
|
||||
foreach ($row->getCells() as $cell_index => $cell) {
|
||||
if ($cell_index == 2) {
|
||||
$namaKota = $cell->getValue();
|
||||
$kota = Kota::where('sKota', 'LIKE', '%'.$namaKota.'%')->first();
|
||||
if ($kota) {
|
||||
$row_data['nIDKota'] = $kota->nID;
|
||||
$row_data['nIDProvinsi'] = $kota->nIDProvinsi;
|
||||
}
|
||||
}
|
||||
else if ($cell_index == 3) {
|
||||
$row_data['sHealthCare'] = $cell->getValue();
|
||||
$row_data['sSlug'] = Str::slug($row_data['sHealthCare']);
|
||||
}
|
||||
else if ($cell_index == 4) {
|
||||
$row_data['sAlamat'] = $cell->getValue();
|
||||
}
|
||||
else if ($cell_index == 5) {
|
||||
$row_data['sTelp'] = $cell->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
// $chunks[] = $row_data;
|
||||
try {
|
||||
// Transaction
|
||||
Healthcare::create($row_data);
|
||||
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
dd($row_data);
|
||||
}
|
||||
}
|
||||
|
||||
if ($chunks && count($chunks) == 100) {
|
||||
Healthcare::insert($chunks);
|
||||
$chunks = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($chunks && count($chunks) > 0) {
|
||||
Healthcare::insert($chunks);
|
||||
$chunks = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
30
database/seeders/RoleSeeder.php
Normal file
30
database/seeders/RoleSeeder.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class RoleSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$roles = [
|
||||
'administrator',
|
||||
'corporate-manager',
|
||||
'hospital-admin'
|
||||
];
|
||||
|
||||
foreach ($roles as $name) {
|
||||
Role::create([
|
||||
'name' => $name
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,7 @@ import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const itemList = [
|
||||
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '08:00 WIB' },
|
||||
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '09:00 WIB' },
|
||||
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '10:00 WIB' },
|
||||
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '11:00 WIB' },
|
||||
{ info: 'Mohon lengkapi dokumen Alison Born', date: 'Selasa, 13 Februari 23', time: '09:43 WIB' },
|
||||
];
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@@ -24,10 +24,7 @@ const ItemStyle = styled(Card)(({ theme }) => ({
|
||||
}));
|
||||
|
||||
const itemList = [
|
||||
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '08:00 WIB' },
|
||||
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '09:00 WIB' },
|
||||
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '10:00 WIB' },
|
||||
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '11:00 WIB' },
|
||||
{ info: 'Mohon lengkapi dokumen Alison Born', date: 'Selasa, 13 Februari 23', time: '09:43 WIB' },
|
||||
];
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
296
frontend/dashboard/src/components/dialogs/DialogDetailClaim.tsx
Normal file
296
frontend/dashboard/src/components/dialogs/DialogDetailClaim.tsx
Normal file
@@ -0,0 +1,296 @@
|
||||
// @mui
|
||||
import {
|
||||
Button,
|
||||
Box,
|
||||
Stepper,
|
||||
Step,
|
||||
StepLabel,
|
||||
Card,
|
||||
Typography,
|
||||
Divider,
|
||||
Stack,
|
||||
CircularProgress,
|
||||
} from '@mui/material';
|
||||
import { Add } from '@mui/icons-material';
|
||||
// components
|
||||
import MuiDialog from '@/components/MuiDialog';
|
||||
// theme
|
||||
import palette from '@/theme/palette';
|
||||
// React
|
||||
import { ReactElement, useEffect, useState } from 'react';
|
||||
import { fDate } from '@/utils/formatTime';
|
||||
import { addMinutes, format } from 'date-fns';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import Iconify from '../Iconify';
|
||||
|
||||
type DataContent = {
|
||||
claim: object;
|
||||
isLoading: boolean;
|
||||
handleDownloadLog: void;
|
||||
};
|
||||
|
||||
type MuiDialogProps = {
|
||||
title?: {
|
||||
name?: string;
|
||||
icon?: string;
|
||||
};
|
||||
openDialog: boolean;
|
||||
setOpenDialog: Function;
|
||||
content?: ReactElement;
|
||||
data?: DataContent[];
|
||||
};
|
||||
|
||||
const steps = ['Review', 'Approval', 'Disbursement'];
|
||||
|
||||
const DialogDetailClaim = ({ title, openDialog, setOpenDialog, data }: MuiDialogProps) => {
|
||||
const claim = data.claim ?? null;
|
||||
|
||||
// ---------------------------------------------
|
||||
// Step
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
useEffect(
|
||||
function () {
|
||||
if (claim?.status == 'requested') {
|
||||
setCurrentStep(0);
|
||||
}
|
||||
if (claim?.status == 'approved') {
|
||||
setCurrentStep(1);
|
||||
}
|
||||
if (claim?.status == 'closed') {
|
||||
setCurrentStep(2);
|
||||
}
|
||||
},
|
||||
[data]
|
||||
);
|
||||
|
||||
// ----------------------------------------------------
|
||||
// Date Stamp
|
||||
let currentDate = null;
|
||||
|
||||
// ----------------------------------------------------
|
||||
// Download LOG
|
||||
const [loadingDownloadLog, setLoadingDownloadLog] = useState(false);
|
||||
const handleDownloadLog = async (claimRequest) => {
|
||||
setLoadingDownloadLog(true);
|
||||
await data.handleDownloadLog(claimRequest).then(() => {
|
||||
setLoadingDownloadLog(false);
|
||||
});
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// Handle Upload Invoice
|
||||
const handleUploadInvoice = () => {
|
||||
enqueueSnackbar('Something went wrong, please contact Link Medis Sehat', { variant: 'error' });
|
||||
};
|
||||
|
||||
const getContent = () => (
|
||||
<>
|
||||
{data.isLoading && (
|
||||
<Stack alignItems="center" justifyContent="space-between" sx={{ p: 4 }}>
|
||||
<CircularProgress />
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{!data.isLoading && (
|
||||
<>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
direction="row"
|
||||
sx={{ marginTop: 1 }}
|
||||
>
|
||||
<Typography variant="subtitle1" sx={{ height: 'max-content' }}>
|
||||
Claim Request
|
||||
</Typography>
|
||||
<Stack>
|
||||
<Typography variant="caption">Submission date</Typography>
|
||||
{/* {JSON.stringify(data)} */}
|
||||
<Typography variant="caption">
|
||||
{claim.created_at && fDate(claim.created_at)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Box sx={{ width: '100%', marginTop: 2 }}>
|
||||
<Stepper alternativeLabel activeStep={currentStep ?? 0}>
|
||||
{steps.map((label) => (
|
||||
<Step key={label}>
|
||||
<StepLabel>{label}</StepLabel>
|
||||
</Step>
|
||||
))}
|
||||
</Stepper>
|
||||
</Box>
|
||||
|
||||
{/* { claim.status == 'approved' && (
|
||||
<Stack sx={{ marginTop: 4}}>
|
||||
<LoadingButton loading={false}
|
||||
variant="contained"
|
||||
startIcon={<Add />}
|
||||
fullWidth
|
||||
// sx={{ typography: 'subtitle2', borderColor: '#F5F5F5' }}
|
||||
onClick={() => {handleUploadInvoice()}}
|
||||
>
|
||||
Upload Invoice
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
)} */}
|
||||
|
||||
{claim.histories_by_date &&
|
||||
claim.histories_by_date.map((historiesByDate) => (
|
||||
<Stack key={historiesByDate.date}>
|
||||
<Stack marginTop={2}>
|
||||
<Typography variant="subtitle1" paddingY={2}>
|
||||
{fDate(historiesByDate.date)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Divider orientation="vertical" flexItem sx={{ borderStyle: 'dashed' }} />
|
||||
<Stack spacing={2} sx={{ flex: 1, maxWidth: '100%' }}>
|
||||
{historiesByDate.histories &&
|
||||
historiesByDate.histories.map((history) => (
|
||||
<Stack key={history.id}>
|
||||
{/* ---------------------------------TYPE INFO------------------------------------ */}
|
||||
<Card sx={{ paddingY: 2, paddingX: 3 }}>
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<Typography variant="body1">
|
||||
{fDate(history.created_at, 'HH:mm')} WIB
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
backgroundColor: palette.light.warning.lighter,
|
||||
color: palette.light.warning.dark,
|
||||
borderColor: palette.light.warning.dark,
|
||||
border: '1px solid',
|
||||
borderRadius: '6px',
|
||||
padding: 1,
|
||||
}}
|
||||
variant="caption"
|
||||
>
|
||||
Request
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Divider sx={{ marginY: 2 }} />
|
||||
<Stack>
|
||||
<Typography variant="subtitle2" color="#404040">
|
||||
{history.title}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="#757575"
|
||||
sx={{ marginTop: 2, marginBottom: 1 }}
|
||||
>
|
||||
{history.description}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
))}
|
||||
|
||||
<Stack direction="row" spacing={2} sx={{ marginTop: 2 }}>
|
||||
<Divider orientation="vertical" flexItem sx={{ borderStyle: 'dashed' }} />
|
||||
<Stack spacing={2} sx={{ flex: 1, maxWidth: '100%' }}>
|
||||
{/* ---------------------------------TYPE INFO------------------------------------ */}
|
||||
<Card sx={{ paddingY: 2, paddingX: 3 }}>
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="center">
|
||||
<Typography variant="body1" fontWeight={600}>
|
||||
<Iconify icon="eva:file-text-fill"></Iconify> Dokumen Kelengkapan
|
||||
</Typography>
|
||||
{/* <Typography
|
||||
sx={{
|
||||
backgroundColor: palette.light.warning.lighter,
|
||||
color: palette.light.warning.dark,
|
||||
borderColor: palette.light.warning.dark,
|
||||
border: '1px solid',
|
||||
borderRadius: '6px',
|
||||
padding: 1,
|
||||
}}
|
||||
variant="caption"
|
||||
>
|
||||
Dokumen
|
||||
</Typography> */}
|
||||
</Stack>
|
||||
<Divider sx={{ marginY: 2 }} />
|
||||
|
||||
<Typography fontWeight="600">Kondisi</Typography>
|
||||
<Stack>
|
||||
<Stack
|
||||
// divider={<Divider orientation="horizontal" flexItem />}
|
||||
spacing={1}
|
||||
sx={{ marginY: 2 }}
|
||||
>
|
||||
{claim.files_by_type?.claim_kondisi &&
|
||||
claim.files_by_type.claim_kondisi.map((file, index) => (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index}>
|
||||
<a href={file.url} target="_blank" style={{ textDecoration: 'none' }}>
|
||||
<Typography sx={{ color: 'text.secondary' }} variant="subtitle2">
|
||||
- {file.name}
|
||||
</Typography>
|
||||
</a>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
|
||||
<Typography fontWeight="600">Diagnosa</Typography>
|
||||
<Stack
|
||||
// divider={<Divider orientation="horizontal" flexItem />}
|
||||
spacing={1}
|
||||
sx={{ marginY: 2 }}
|
||||
>
|
||||
{claim.files_by_type?.claim_diagnosis &&
|
||||
claim.files_by_type.claim_diagnosis.map((file, index) => (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index}>
|
||||
<a href={file.url} target="_blank" style={{ textDecoration: 'none' }}>
|
||||
<Typography sx={{ color: 'text.secondary' }} variant="subtitle2">
|
||||
- {file.name}
|
||||
</Typography>
|
||||
</a>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
|
||||
<Typography fontWeight="600">Hasil</Typography>
|
||||
<Stack
|
||||
divider={<Divider orientation="horizontal" flexItem />}
|
||||
spacing={1}
|
||||
sx={{ marginY: 2 }}
|
||||
>
|
||||
{claim.files_by_type?.result &&
|
||||
claim.files_by_type.result.map((file, index) => (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index}>
|
||||
<a href={file.url} target="_blank" style={{ textDecoration: 'none' }}>
|
||||
<Typography sx={{ color: 'text.secondary' }} variant="subtitle2">
|
||||
- {file.name}
|
||||
</Typography>
|
||||
</a>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<MuiDialog
|
||||
title={title}
|
||||
openDialog={openDialog}
|
||||
setOpenDialog={setOpenDialog}
|
||||
content={getContent()}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DialogDetailClaim;
|
||||
@@ -58,6 +58,13 @@ const navConfig = [
|
||||
{ title: 'Hospitals', path: '/hospitals' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'LOG REQUEST',
|
||||
path: '/claim-requests',
|
||||
// children: [
|
||||
// { title: 'Request', path: '/case-request' },
|
||||
// ],
|
||||
},
|
||||
{
|
||||
title: 'CASE MANAGEMENT',
|
||||
path: '/claims',
|
||||
|
||||
64
frontend/dashboard/src/pages/ClaimRequests/CreateUpdate.tsx
Executable file
64
frontend/dashboard/src/pages/ClaimRequests/CreateUpdate.tsx
Executable file
@@ -0,0 +1,64 @@
|
||||
import * as Yup from 'yup';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { Autocomplete, Button, Card, Collapse, Container, Divider, Grid, Stack, Table, TableBody, TableCell, TableRow, TextField, Typography } from '@mui/material';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs';
|
||||
import { FormProvider, RHFCheckbox, RHFSelect, RHFTextField } from '../../components/hook-form';
|
||||
import Page from '../../components/Page';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import MemberSelectDialog from '../../components/dialogs/MemberSelectDialog';
|
||||
import { styled } from '@mui/system';
|
||||
import axios from '../../utils/axios';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { fCurrency } from '../../utils/formatNumber';
|
||||
import Iconify from '../../components/Iconify';
|
||||
import Form from './Form';
|
||||
|
||||
export default function ClaimsCreateUpdate() {
|
||||
|
||||
const { themeStretch } = useSettings();
|
||||
const { id } = useParams();
|
||||
|
||||
const isEdit = id ? true : false;
|
||||
|
||||
const [currentClaim, setCurrentClaim] = useState();
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit) {
|
||||
axios.get('/claims/' + id).then((res) => {
|
||||
// console.log('Yeet', res.data);
|
||||
setCurrentClaim(res.data);
|
||||
});
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
|
||||
return (
|
||||
<Page title={isEdit ? `Edit Claim : ${currentClaim?.id}` : "Create New Claim"}>
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<Stack direction="row" alignItems="center">
|
||||
<HeaderBreadcrumbs
|
||||
heading={
|
||||
!isEdit
|
||||
? 'Create New Claim'
|
||||
: `Edit Claim : ${currentClaim?.code}`
|
||||
}
|
||||
links={[
|
||||
{ name: 'Dashboard', href: '/dashboard' },
|
||||
{
|
||||
name: 'Claim',
|
||||
href: '/claims',
|
||||
},
|
||||
{ name: !isEdit ? 'Create' : currentClaim?.id ?? '' },
|
||||
]}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<Form isEdit={isEdit} currentClaim={currentClaim} />
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
596
frontend/dashboard/src/pages/ClaimRequests/Form.tsx
Normal file
596
frontend/dashboard/src/pages/ClaimRequests/Form.tsx
Normal file
@@ -0,0 +1,596 @@
|
||||
import * as Yup from 'yup';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import axios from '../../utils/axios';
|
||||
import { FormProvider, RHFTextField } from '../../components/hook-form';
|
||||
import {
|
||||
Autocomplete,
|
||||
Button,
|
||||
Grid,
|
||||
Stack,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
useTheme,
|
||||
List,
|
||||
ListItem,
|
||||
IconButton,
|
||||
ListItemAvatar,
|
||||
Avatar,
|
||||
ListItemText,
|
||||
} from '@mui/material';
|
||||
import Iconify from '../../components/Iconify';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { fCurrency } from '../../utils/formatNumber';
|
||||
import MemberSelectDialog from '../../components/dialogs/MemberSelectDialog';
|
||||
import { Add, DeleteOutline } from '@mui/icons-material';
|
||||
|
||||
type Props = {
|
||||
isEdit: boolean;
|
||||
currentClaim?: any;
|
||||
};
|
||||
|
||||
export default function ClaimForm({ isEdit, currentClaim }: Props) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const NewCorporateSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
code: Yup.string().required('Corporate Code is required'),
|
||||
active: Yup.boolean().required('Corporate Status is required'),
|
||||
// file: Yup.boolean().required('Corporate Status is required'),
|
||||
});
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
member: currentClaim?.member || {},
|
||||
member_id: currentClaim?.member_id || null,
|
||||
diagnosis_id: currentClaim?.diagnosis_id || null,
|
||||
total_claim: currentClaim?.total_claim || 0,
|
||||
}),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[currentClaim]
|
||||
);
|
||||
|
||||
const methods = useForm<any>({
|
||||
resolver: yupResolver(NewCorporateSchema),
|
||||
defaultValues,
|
||||
});
|
||||
const {
|
||||
reset,
|
||||
watch,
|
||||
control,
|
||||
setValue,
|
||||
getValues,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
const values = watch();
|
||||
|
||||
const [isCheckingLimit, setIsCheckingLimit] = useState(false);
|
||||
const [isEligible, setIsEligible] = useState(false);
|
||||
const [memberBenefits, setMemberBenefits] = useState([]);
|
||||
const [diagnosisOption, setDiagnosisOption] = useState([]);
|
||||
const [isMemberDialogOpen, setIsMemberDialogOpen] = useState(false);
|
||||
const [member, setMember] = useState({})
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
console.log('defaultValues', defaultValues);
|
||||
if (isEdit && currentClaim) {
|
||||
reset(defaultValues);
|
||||
setMember(defaultValues.member)
|
||||
}
|
||||
if (!isEdit) {
|
||||
reset(defaultValues);
|
||||
setMember(defaultValues.member)
|
||||
}
|
||||
}, [isEdit, currentClaim]);
|
||||
|
||||
const fileSelected = (event, type) => {
|
||||
const files = event.target.files;
|
||||
const currentFiles = getValues(`uploaded_files.${type}`) ?? [];
|
||||
|
||||
setValue(`uploaded_files.${type}`, [...currentFiles, ...files]);
|
||||
|
||||
console.log('currentFiles', getValues('uploaded_files'));
|
||||
};
|
||||
|
||||
const memberSelected = (member) => {
|
||||
setMember(member)
|
||||
};
|
||||
|
||||
const checkLimit = async () => {
|
||||
console.log('CHECKING LIMIT');
|
||||
};
|
||||
|
||||
const onSubmit = async (data: any) => {
|
||||
try {
|
||||
if (!isEdit) {
|
||||
const response = await axios.post('/claims', data);
|
||||
} else {
|
||||
const response = await axios.put('/claims/' + currentClaim?.id ?? '', data);
|
||||
}
|
||||
reset();
|
||||
enqueueSnackbar(
|
||||
!isEdit ? 'Organizations Created Successfully!' : 'Organizations Udpated Successfully!',
|
||||
{ variant: 'success' }
|
||||
);
|
||||
navigate('/claims');
|
||||
} catch (error: any) {
|
||||
if (error && error.response.status === 422) {
|
||||
for (const [key, value] of Object.entries(error.response.data.errors)) {
|
||||
setError(key, { message: value[0] });
|
||||
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
|
||||
}
|
||||
} else {
|
||||
enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' });
|
||||
}
|
||||
}
|
||||
|
||||
const ascent = document?.querySelector('ascent');
|
||||
if (ascent != null) {
|
||||
ascent.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
function generate(files, element: React.ReactElement) {
|
||||
return files.map((value) =>
|
||||
React.cloneElement(element, {
|
||||
key: value,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const headStyle = {};
|
||||
return (
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">Member</Typography>
|
||||
|
||||
<Stack spacing={2} direction="row">
|
||||
<Grid item xs={12}>
|
||||
<RHFTextField
|
||||
name="member_id"
|
||||
label="Member"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
value={member?.name || ''}
|
||||
InputProps={{
|
||||
readOnly: true,
|
||||
}}
|
||||
onClick={() => {
|
||||
if (!isEdit) setIsMemberDialogOpen(true);
|
||||
if (isEdit) enqueueSnackbar('Cannot Change Member', { variant: 'error' });
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
{/* <Grid item xs={2}>
|
||||
<Button variant="outlined" fullWidth sx={{ p: 1.8 }} onClick={() => {
|
||||
setIsMemberDialogOpen(true)
|
||||
}}>
|
||||
{member ? 'Change' : 'Search'}
|
||||
</Button>
|
||||
</Grid> */}
|
||||
</Stack>
|
||||
|
||||
{member?.id && (
|
||||
<Stack>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Table border="light-700">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Name
|
||||
</TableCell>
|
||||
<TableCell align="left">{member?.full_name}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
DOB
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{member?.birth_date} ({member?.age + ' years'})
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Marital Status
|
||||
</TableCell>
|
||||
<TableCell align="left">{member?.marital_status}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Record Type
|
||||
</TableCell>
|
||||
<TableCell align="left">{member?.record_type}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Principal ID
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{member?.principal_id} (
|
||||
{member?.relation_with_principal})
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Table border="light-700">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Plan
|
||||
</TableCell>
|
||||
<TableCell align="left">{member?.current_plan?.code}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Active
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{member?.current_plan?.start} -{' '}
|
||||
{member?.current_plan?.end} (Active)
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Corporate Limit
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{fCurrency(0)} / {fCurrency(member?.current_plan?.limit_rules)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Plan Usage
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{fCurrency(0)} / {fCurrency(member?.current_plan?.limit_rules)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<Controller
|
||||
name="benefit"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Autocomplete
|
||||
options={memberBenefits}
|
||||
getOptionLabel={(option) =>
|
||||
option ? `#${option.id} (${option.code}) ${option.description}` : ''
|
||||
}
|
||||
value={value || ''}
|
||||
onChange={(event: any, newValue: any) => {
|
||||
setValue('benefit_id', newValue?.id);
|
||||
onChange(newValue);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
name="benefit"
|
||||
{...params}
|
||||
label="Benefit"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
// onKeyPress={(event) => {
|
||||
// if (event.key === 'Enter')
|
||||
// searchDiagnosis(event.target.value)
|
||||
// }}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Controller
|
||||
name="diagnosis"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Autocomplete
|
||||
options={diagnosisOption}
|
||||
getOptionLabel={(option) => (option ? `(${option.code}) ${option.name}` : '')}
|
||||
value={value || ''}
|
||||
onChange={(event: any, newValue: any) => {
|
||||
setValue('diagnosis_id', newValue?.id);
|
||||
// setValue('diagnosis', newValue)
|
||||
onChange(newValue);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
name="diagnosis"
|
||||
{...params}
|
||||
label="Diagnosis"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
onKeyPress={(event) => {
|
||||
if (event.key === 'Enter') searchDiagnosis(event.target.value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
{isCheckingLimit && (
|
||||
<Stack
|
||||
sx={{
|
||||
backgroundColor: 'gray',
|
||||
paddingY: 1,
|
||||
paddingX: 1.5,
|
||||
mb: 2,
|
||||
borderRadius: '3-xl',
|
||||
}}
|
||||
>
|
||||
{/* Checking */}
|
||||
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:info-circle"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Please Wait, Checking Eligibilty
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{false && isCheckingLimit == false && isEligible == null && (
|
||||
<Stack
|
||||
sx={{
|
||||
backgroundColor: 'gray',
|
||||
paddingY: 1,
|
||||
paddingX: 1.5,
|
||||
mb: 2,
|
||||
borderRadius: '3-xl',
|
||||
}}
|
||||
>
|
||||
{/* No Data Selected */}
|
||||
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:info-circle"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Please Select Diagnosis !
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{!isCheckingLimit && isEligible !== null && isEligible && (
|
||||
<Stack
|
||||
sx={{
|
||||
backgroundColor: '#B2E8E8',
|
||||
paddingY: 1,
|
||||
paddingX: 1.5,
|
||||
mb: 2,
|
||||
borderRadius: '3-xl',
|
||||
}}
|
||||
>
|
||||
{/* Eligible */}
|
||||
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:lock-alt"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Diagnosis is Eligible
|
||||
</Typography>
|
||||
</Typography>
|
||||
<Typography sx={{ typography: 'caption', color: '#637381' }}>
|
||||
125.000.000 / 125.000.000
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{!isCheckingLimit && isEligible !== null && !isEligible && (
|
||||
<Stack
|
||||
sx={{
|
||||
backgroundColor: '#B2E8E8',
|
||||
paddingY: 1,
|
||||
paddingX: 1.5,
|
||||
mb: 2,
|
||||
borderRadius: '3-xl',
|
||||
}}
|
||||
>
|
||||
{/* Not Eligible */}
|
||||
{/* <Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:lock-alt"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Not Eligible
|
||||
</Typography>
|
||||
</Typography>
|
||||
<Typography sx={{ typography: 'caption', color: '#637381' }}>
|
||||
125.000.000 / 125.000.000
|
||||
</Typography> */}
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<RHFTextField type="number" name="total_claim" label="Total Claim" />
|
||||
|
||||
{isEdit && (
|
||||
<React.Fragment>
|
||||
<Typography variant="h6">Documents</Typography>
|
||||
|
||||
<List>
|
||||
{(getValues('uploaded_files.invoice') && getValues('uploaded_files.invoice').length
|
||||
? getValues('uploaded_files.invoice')
|
||||
: []
|
||||
).map((file, index) => (
|
||||
<ListItem
|
||||
secondaryAction={
|
||||
<IconButton edge="end" aria-label="delete">
|
||||
<DeleteOutline />
|
||||
</IconButton>
|
||||
}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
{/* <FileIcon /> */}
|
||||
I
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={file.name} secondary={file.type} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<Add />}
|
||||
component="label"
|
||||
sx={{ paddingY: 2, width: '100%', ':hover': { border: 'none' } }}
|
||||
>
|
||||
Invoice
|
||||
<input
|
||||
name="invoice"
|
||||
hidden
|
||||
accept="image/*,application/pdf"
|
||||
multiple
|
||||
type="file"
|
||||
onChange={(event) => {
|
||||
fileSelected(event, 'invoice');
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
<List>
|
||||
{(getValues('uploaded_files.prescription') && getValues('uploaded_files.prescription').length
|
||||
? getValues('uploaded_files.prescription')
|
||||
: []
|
||||
).map((file, index) => (
|
||||
<ListItem
|
||||
secondaryAction={
|
||||
<IconButton edge="end" aria-label="delete">
|
||||
<DeleteOutline />
|
||||
</IconButton>
|
||||
}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
{/* <FileIcon /> */}
|
||||
P
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={file.name} secondary={file.type} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<Add />}
|
||||
component="label"
|
||||
sx={{ paddingY: 2, width: '100%', ':hover': { border: 'none' } }}
|
||||
>
|
||||
Prescription
|
||||
<input
|
||||
name="prescription"
|
||||
hidden
|
||||
accept="image/*,application/pdf"
|
||||
multiple
|
||||
type="file"
|
||||
onChange={(event) => {
|
||||
fileSelected(event, 'prescription');
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
|
||||
<List>
|
||||
{(getValues('uploaded_files.diagnosis') && getValues('uploaded_files.diagnosis').length
|
||||
? getValues('uploaded_files.diagnosis')
|
||||
: []
|
||||
).map((file, index) => (
|
||||
<ListItem
|
||||
secondaryAction={
|
||||
<IconButton edge="end" aria-label="delete">
|
||||
<DeleteOutline />
|
||||
</IconButton>
|
||||
}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
{/* <FileIcon /> */}
|
||||
DR
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={file.name} secondary={file.type} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<Add />}
|
||||
component="label"
|
||||
sx={{ paddingY: 2, width: '100%', ':hover': { border: 'none' } }}
|
||||
>
|
||||
Doctor Result
|
||||
<input
|
||||
name="invoice"
|
||||
hidden
|
||||
accept="image/*,application/pdf"
|
||||
multiple
|
||||
type="file"
|
||||
onChange={(event) => {
|
||||
fileSelected(event, 'diagnosis');
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{isEligible === true ? (
|
||||
<LoadingButton
|
||||
onClick={handleSubmit(onSubmit)}
|
||||
variant="contained"
|
||||
color="success"
|
||||
style={{ color: '#ffffff' }}
|
||||
size="large"
|
||||
fullWidth={true}
|
||||
loading={isCheckingLimit}
|
||||
>
|
||||
Create Claim
|
||||
</LoadingButton>
|
||||
) : (
|
||||
<LoadingButton
|
||||
onClick={checkLimit}
|
||||
variant="outlined"
|
||||
size="large"
|
||||
fullWidth={true}
|
||||
loading={isCheckingLimit}
|
||||
>
|
||||
Check Limit
|
||||
</LoadingButton>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
<MemberSelectDialog
|
||||
openDialog={isMemberDialogOpen}
|
||||
setOpenDialog={setIsMemberDialogOpen}
|
||||
onSelect={memberSelected}
|
||||
></MemberSelectDialog>
|
||||
</FormProvider>
|
||||
);
|
||||
}
|
||||
30
frontend/dashboard/src/pages/ClaimRequests/Index.tsx
Executable file
30
frontend/dashboard/src/pages/ClaimRequests/Index.tsx
Executable file
@@ -0,0 +1,30 @@
|
||||
import { Card, Stack } from "@mui/material";
|
||||
import HeaderBreadcrumbs from "../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../components/Page";
|
||||
import List from "./List";
|
||||
|
||||
|
||||
|
||||
export default function Claims() {
|
||||
|
||||
const pageTitle = 'Claim Request';
|
||||
return (
|
||||
<Page title={ pageTitle } sx={{ mx: 2}}>
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
heading={ pageTitle }
|
||||
links={[
|
||||
{ name: 'Dashboard', href: '/dashboard' },
|
||||
{
|
||||
name: 'Claim Request',
|
||||
href: '/claim-requests',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
{/* <Stack> */}
|
||||
<List />
|
||||
{/* </Stack> */}
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
339
frontend/dashboard/src/pages/ClaimRequests/List.tsx
Executable file
339
frontend/dashboard/src/pages/ClaimRequests/List.tsx
Executable file
@@ -0,0 +1,339 @@
|
||||
// @mui
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
Collapse,
|
||||
IconButton,
|
||||
MenuItem,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
Stack,
|
||||
Menu,
|
||||
ButtonGroup,
|
||||
Link,
|
||||
Chip,
|
||||
} from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
// hooks
|
||||
import React, { ChangeEvent, useEffect, useRef, useState } from 'react';
|
||||
import { Navigate, useNavigate, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../utils/axios';
|
||||
import { LaravelPaginatedData, LaravelPaginatedDataDefault } from '../../@types/paginated-data';
|
||||
import DataTable from '../../components/LaravelTable';
|
||||
import { fCurrency } from '../../utils/formatNumber';
|
||||
import EditRoundedIcon from '@mui/icons-material/EditRounded';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { Divider } from '@mui/material';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import DialogDetailClaim from '@/components/dialogs/DialogDetailClaim';
|
||||
// import LoadingButton from '@/theme/overrides/LoadingButton';
|
||||
|
||||
export default function List() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? '';
|
||||
setSearchText(newSearchText);
|
||||
};
|
||||
|
||||
const handleSearchSubmit = (event: any) => {
|
||||
event.preventDefault();
|
||||
props.onSearch({ search: searchText }); // Trigger to Parent
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// Trigger First Search
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
ref={searchInput}
|
||||
label="Search"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
onChange={handleSearchChange}
|
||||
value={searchText}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
function ImportForm(props: any) {
|
||||
// IMPORT
|
||||
// Create Button Menu
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const createMenu = Boolean(anchorEl);
|
||||
const importForm = useRef<HTMLInputElement>(null);
|
||||
const [currentImportFileName, setCurrentImportFileName] = useState(null);
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
{/* <Button
|
||||
variant="outlined"
|
||||
startIcon={<AddIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
onClick={() => {
|
||||
navigate('/claims/create');
|
||||
}}
|
||||
>
|
||||
Create
|
||||
</Button> */}
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>(
|
||||
LaravelPaginatedDataDefault
|
||||
);
|
||||
|
||||
const loadDataTableData = async (appliedFilter: any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/claim-requests', { params: filter });
|
||||
// console.log(response.data);
|
||||
setDataTableLoading(false);
|
||||
|
||||
setDataTableData(response.data);
|
||||
};
|
||||
|
||||
const applyFilter = async (searchFilter: { search: string }) => {
|
||||
await loadDataTableData(searchFilter);
|
||||
setSearchParams(searchFilter);
|
||||
};
|
||||
|
||||
const handlePageChange = (event: ChangeEvent, value: number): void => {
|
||||
const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]);
|
||||
loadDataTableData(filter);
|
||||
setSearchParams(filter);
|
||||
};
|
||||
|
||||
const handleApprove = (claimRequest) => {
|
||||
axios.post(`claim-requests/${claimRequest.id}/approve`)
|
||||
.then((response) => {
|
||||
enqueueSnackbar('Success Approve', {variant: 'success'})
|
||||
loadDataTableData()
|
||||
})
|
||||
.catch(({response}) => {
|
||||
enqueueSnackbar(response.data.message ?? 'Something went wrong!', {variant : "error"})
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, []);
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData(data: any): any {
|
||||
return {
|
||||
...data,
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
/* ------------------ TABLE ROW ------------------ */
|
||||
}
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [loadingApprove, setLoadingApprove] = React.useState(false);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell>
|
||||
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.member?.full_name}</TableCell>
|
||||
<TableCell align="left">{row.submission_date}</TableCell>
|
||||
<TableCell align="left">{row.service_type}</TableCell>
|
||||
<TableCell align="right"><Chip label={row.status}/></TableCell>
|
||||
<TableCell align="right">{ row.status == 'requested' && (<LoadingButton loading={loadingApprove} variant="outlined" onClick={() => {handleApprove(row)}}>Approve</LoadingButton> )}</TableCell>
|
||||
<TableCell>
|
||||
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
handleShowClaim(row);
|
||||
}}
|
||||
>
|
||||
<Iconify icon="eva:eye-fill" />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ borderBottom: 1 }}>
|
||||
<Stack
|
||||
divider={<Divider orientation="horizontal" flexItem />}
|
||||
spacing={1}
|
||||
sx={{ marginY: 2 }}
|
||||
>
|
||||
<Box>
|
||||
<Typography fontWeight={600}>Berkas Hasil Penunjang</Typography>
|
||||
{row.files_by_type?.result &&
|
||||
row.files_by_type?.result.map((file, index) => (
|
||||
<Stack direction="row" key={index}>
|
||||
<Typography sx={{marginRight: 2}}>-</Typography> <a href={file.url} target="_blank">{file.name}</a>
|
||||
</Stack>
|
||||
))}
|
||||
|
||||
{ !row.files_by_type?.result && (
|
||||
<Typography>Tidak ada berkas</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
{
|
||||
/* ------------------ END TABLE ROW ------------------ */
|
||||
}
|
||||
|
||||
function TableContent() {
|
||||
return (
|
||||
<Table aria-label="collapsible table">
|
||||
{/* ------------------ TABLE HEADER ------------------ */}
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
<TableCell style={headStyle} align="left">
|
||||
Code
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Member Name
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Submission Date
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Jenis Layanan
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Status
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="right">
|
||||
Action
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
{/* ------------------ END TABLE HEADER ------------------ */}
|
||||
|
||||
{/* ------------------ TABLE ROW ------------------ */}
|
||||
{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>
|
||||
)}
|
||||
{/* ------------------ END TABLE ROW ------------------ */}
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Dialog Detail Claim Request
|
||||
const [openDialogDetailClaim, setOpenDialogDetailClaim] = useState(false);
|
||||
const [loadingClaimDetail, setLoadingClaimDetail] = useState(true);
|
||||
const [currentClaim, setCurrentClaim] = useState(null);
|
||||
|
||||
function handleShowClaim(claimRequest) {
|
||||
setLoadingClaimDetail(true);
|
||||
setOpenDialogDetailClaim(true);
|
||||
|
||||
axios.get(`/claim-requests/${claimRequest.id}`)
|
||||
.then(({data}) => {
|
||||
setCurrentClaim(data.data);
|
||||
setLoadingClaimDetail(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
enqueueSnackbar(err.message, {variant: 'error'})
|
||||
})
|
||||
}
|
||||
|
||||
function handleDownloadLog() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<ImportForm />
|
||||
|
||||
<DataTable
|
||||
isLoading={dataTableIsLoading}
|
||||
lastRequest={0}
|
||||
data={dataTableData}
|
||||
handlePageChange={handlePageChange}
|
||||
TableContent={<TableContent />}
|
||||
/>
|
||||
|
||||
|
||||
<DialogDetailClaim
|
||||
openDialog={openDialogDetailClaim}
|
||||
setOpenDialog={setOpenDialogDetailClaim}
|
||||
title={{ name: 'Claim Request Detail' }}
|
||||
data={{ claim: currentClaim, isLoading: loadingClaimDetail, handleDownloadLog }}
|
||||
></DialogDetailClaim>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -46,6 +46,7 @@ import { Member } from '../../../@types/member';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import DialogLog from './sections/DialogLog';
|
||||
|
||||
export default function CorporatePlanList() {
|
||||
const { themeStretch } = useSettings();
|
||||
@@ -198,19 +199,17 @@ export default function CorporatePlanList() {
|
||||
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();
|
||||
})
|
||||
}
|
||||
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 (
|
||||
<div>
|
||||
@@ -248,7 +247,13 @@ export default function CorporatePlanList() {
|
||||
}}
|
||||
>
|
||||
<MenuItem onClick={handleImportButton}>Import</MenuItem>
|
||||
<MenuItem onClick={() => {handleGetTemplate('member')}}>Download Template</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
handleGetTemplate('member');
|
||||
}}
|
||||
>
|
||||
Download Template
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Stack>
|
||||
)}
|
||||
@@ -329,6 +334,15 @@ export default function CorporatePlanList() {
|
||||
const { row } = props;
|
||||
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) => {
|
||||
axios
|
||||
.put(`/members/${row.id}/activation`, {
|
||||
@@ -355,33 +369,7 @@ export default function CorporatePlanList() {
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const handleDownloadLog = (row: ReturnType<typeof createData>) => {
|
||||
setLoadingLog(true);
|
||||
axios.get(`generate-log/${row.id}`, {
|
||||
responseType: 'blob'
|
||||
})
|
||||
.then((response) => {
|
||||
window.open(URL.createObjectURL(response.data));
|
||||
// const content = response.headers['content-type'];
|
||||
// download(response.data, file.file_name, content);
|
||||
// const link = document.createElement('a');
|
||||
// console.log(response.data);
|
||||
// link.href = response.data.data.file_url;
|
||||
// link.setAttribute('download', response.data.data.file_name);
|
||||
// document.body.appendChild(link);
|
||||
// link.click();
|
||||
setLoadingLog(false);
|
||||
})
|
||||
// .then((blobFile) => {
|
||||
// new File([blobFile], 'asdads.pdf', { type: blobFile.type })
|
||||
// setLoadingLog(false);
|
||||
// })
|
||||
.catch((response) => {
|
||||
enqueueSnackbar(response.message, {variant: 'error'})
|
||||
setLoadingLog(false);
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
@@ -546,31 +534,29 @@ export default function CorporatePlanList() {
|
||||
</Grid>
|
||||
|
||||
<Grid>
|
||||
<LoadingButton
|
||||
id="upload-button"
|
||||
variant="outlined"
|
||||
startIcon={<InsertDriveFileIcon />}
|
||||
// sx={{ p: 1.8 }}
|
||||
onClick={() => {handleDownloadLog(row)}}
|
||||
loading={loadingLog}
|
||||
>
|
||||
Download LOG
|
||||
</LoadingButton>
|
||||
<LoadingButton
|
||||
id="upload-button"
|
||||
variant="outlined"
|
||||
startIcon={<InsertDriveFileIcon />}
|
||||
// sx={{ p: 1.8 }}
|
||||
// onClick={() => {handleDownloadLog(row)}}
|
||||
onClick={() => {
|
||||
setDialogLogOpen(true);
|
||||
}}
|
||||
loading={loadingLog}
|
||||
>
|
||||
Download LOG
|
||||
</LoadingButton>
|
||||
</Grid>
|
||||
|
||||
{/* <Typography sx={{ fontWeight: '600', mb: 1, mt: 2 }}>Sub Corporate</Typography>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Sub Corporates (asdasdasdasd)
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: qweqweqweqwe
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid> */}
|
||||
<DialogLog
|
||||
title={{
|
||||
name: `Generate LOG - ${row.full_name}`,
|
||||
}}
|
||||
openDialog={dialogLogOpen}
|
||||
setOpenDialog={setDialogLogOpen}
|
||||
data={{ member: row }}
|
||||
></DialogLog>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
|
||||
@@ -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;
|
||||
@@ -270,6 +270,10 @@ export default function Router() {
|
||||
path: 'claims',
|
||||
element: <Claims />,
|
||||
},
|
||||
{
|
||||
path: 'claim-requests',
|
||||
element: <ClaimRequests />,
|
||||
},
|
||||
{
|
||||
path: 'claims/create',
|
||||
element: <ClaimsCreate />,
|
||||
@@ -398,3 +402,5 @@ const Profile = Loadable(lazy(() => import('../pages/Profile/Index')));
|
||||
|
||||
const Claims = Loadable(lazy(() => import('../pages/Claims/Index')));
|
||||
const ClaimsCreate = Loadable(lazy(() => import('../pages/Claims/CreateUpdate')));
|
||||
|
||||
const ClaimRequests = Loadable(lazy(() => import('../pages/ClaimRequests/Index')));
|
||||
4
frontend/hospital-portal/.env.development
Normal file
4
frontend/hospital-portal/.env.development
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
REACT_APP_HOST_API_URL="http://localhost:8000"
|
||||
|
||||
VITE_API_URL="http://localhost:8000/api/hospitalportal"
|
||||
1
frontend/hospital-portal/.env.staging
Normal file
1
frontend/hospital-portal/.env.staging
Normal file
@@ -0,0 +1 @@
|
||||
VITE_API_URL="https://aso-api.linksehat.dev/api/hospitalportal"
|
||||
8
frontend/hospital-portal/.eslintignore
Executable file
8
frontend/hospital-portal/.eslintignore
Executable file
@@ -0,0 +1,8 @@
|
||||
// .eslintignore
|
||||
build/*
|
||||
public/*
|
||||
src/react-app-env.d.ts
|
||||
src/reportWebVitals.ts
|
||||
src/service-worker.ts
|
||||
src/serviceWorkerRegistration.ts
|
||||
src/setupTests.ts
|
||||
54
frontend/hospital-portal/.eslintrc
Executable file
54
frontend/hospital-portal/.eslintrc
Executable file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"plugins": [
|
||||
"prettier",
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"airbnb-typescript",
|
||||
"react-app",
|
||||
"prettier"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": [
|
||||
"**/tsconfig.json"
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"typescript": {
|
||||
"alwaysTryTypes": true,
|
||||
"exceptAfterSingleLine": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"react/jsx-key": 2,
|
||||
"arrow-body-style": 1,
|
||||
"import/no-duplicates": 1,
|
||||
"react/self-closing-comp": 1,
|
||||
"@typescript-eslint/no-shadow": 0,
|
||||
"import/no-useless-path-segments": 1,
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"@typescript-eslint/naming-convention": 0,
|
||||
"import/extensions": "never",
|
||||
"object-curly-spacing": [
|
||||
1,
|
||||
"always"
|
||||
],
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
1,
|
||||
{
|
||||
"vars": "all",
|
||||
"args": "none"
|
||||
}
|
||||
],
|
||||
"prefer-destructuring": [
|
||||
1,
|
||||
{
|
||||
"object": true,
|
||||
"array": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
26
frontend/hospital-portal/.gitignore
vendored
Executable file
26
frontend/hospital-portal/.gitignore
vendored
Executable file
@@ -0,0 +1,26 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
/.env
|
||||
/.env.local
|
||||
/.env.development.local
|
||||
/.env.test.local
|
||||
/.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
.eslintcache
|
||||
12
frontend/hospital-portal/.htaccess
Executable file
12
frontend/hospital-portal/.htaccess
Executable file
@@ -0,0 +1,12 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule (.*) /index.html [QSA,L]
|
||||
</IfModule>
|
||||
|
||||
<IfModule pagespeed_module>
|
||||
ModPagespeed off
|
||||
</IfModule>
|
||||
22
frontend/hospital-portal/.pnpm-debug.log
Executable file
22
frontend/hospital-portal/.pnpm-debug.log
Executable file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"0 debug pnpm:scope": {
|
||||
"selected": 1
|
||||
},
|
||||
"1 error pnpm": {
|
||||
"code": "ELIFECYCLE",
|
||||
"errno": "ENOENT",
|
||||
"syscall": "spawn",
|
||||
"file": "sh",
|
||||
"pkgid": "@minimal/material-kit-react@3.2.0",
|
||||
"stage": "start",
|
||||
"script": "vite",
|
||||
"pkgname": "@minimal/material-kit-react",
|
||||
"err": {
|
||||
"name": "pnpm",
|
||||
"message": "@minimal/material-kit-react@3.2.0 start: `vite`\nspawn ENOENT",
|
||||
"code": "ELIFECYCLE",
|
||||
"stack": "pnpm: @minimal/material-kit-react@3.2.0 start: `vite`\nspawn ENOENT\n at ChildProcess.<anonymous> (/home/dell/.nvm/versions/node/v16.13.0/pnpm-global/5/node_modules/.pnpm/pnpm@7.0.0/node_modules/pnpm/dist/pnpm.cjs:93294:22)\n at ChildProcess.emit (node:events:390:28)\n at maybeClose (node:internal/child_process:1064:16)\n at Process.ChildProcess._handle.onexit (node:internal/child_process:301:5)"
|
||||
}
|
||||
},
|
||||
"2 warn pnpm:global": " Local package.json exists, but node_modules missing, did you mean to install?"
|
||||
}
|
||||
6
frontend/hospital-portal/.prettierrc
Executable file
6
frontend/hospital-portal/.prettierrc
Executable file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 2
|
||||
}
|
||||
36
frontend/hospital-portal/index.html
Executable file
36
frontend/hospital-portal/index.html
Executable file
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<!-- Favicon -->
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png">
|
||||
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
|
||||
<!-- Using Google Font -->
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Public+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- Using Local Font -->
|
||||
<link rel="stylesheet" type="text/css" href="/fonts/index.css" />
|
||||
|
||||
<title>Dashboard</title>
|
||||
<meta name="description"
|
||||
content="The starting point for your next project with Minimal UI Kit, built on the newest version of Material-UI ©, ready to be customized to your style" />
|
||||
<meta name="keywords" content="react,material,kit,application,dashboard,admin,template" />
|
||||
<meta name="author" content="Minimal UI Kit" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
15880
frontend/hospital-portal/package-lock.json
generated
Executable file
15880
frontend/hospital-portal/package-lock.json
generated
Executable file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user