Merge branch 'feature/hospital-portal'
0
Modules/HospitalPortal/Config/.gitkeep
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/Database/Migrations/.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/Entities/.gitkeep
Normal file
0
Modules/HospitalPortal/Http/Controllers/.gitkeep
Normal 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,97 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\HospitalPortal\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\ClaimRequest;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
|
||||
class ClaimRequestController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$claimRequests = ClaimRequest::query()
|
||||
->with(['member'])
|
||||
->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([
|
||||
// 'submission_date' => 'required',
|
||||
'member_id' => 'required',
|
||||
// 'files' => ''
|
||||
]);
|
||||
|
||||
$newClaimRequest = ClaimRequest::create([
|
||||
'member_id' => $request->member_id,
|
||||
'submission_date' => now(),
|
||||
'status' => 'requested'
|
||||
]);
|
||||
|
||||
return Helper::responseJson(data: $newClaimRequest, message: 'Claim Request berhasil ajukan!');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,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
@@ -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/Requests/.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
@@ -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/js/app.js
Normal file
0
Modules/HospitalPortal/Resources/lang/.gitkeep
Normal file
0
Modules/HospitalPortal/Resources/views/.gitkeep
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
42
Modules/HospitalPortal/Routes/api.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?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');
|
||||
});
|
||||
});
|
||||
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/Unit/.gitkeep
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
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Internal\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\ClaimRequest;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
|
||||
class ClaimRequestController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$claimRequests = ClaimRequest::query()
|
||||
->with(['member'])
|
||||
->paginate();
|
||||
|
||||
return $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)
|
||||
{
|
||||
return view('internal::show');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return view('internal::edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
* @param int $id
|
||||
* @return Renderable
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function approve($id)
|
||||
{
|
||||
$claimRequest = ClaimRequest::findOrFail($id);
|
||||
|
||||
$claimRequest->status = 'approved';
|
||||
$claimRequest->save();
|
||||
|
||||
// Generate LOG
|
||||
|
||||
return $claimRequest;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ use Modules\Internal\Http\Controllers\Api\AuthController;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Internal\Http\Controllers\Api\BenefitController;
|
||||
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;
|
||||
@@ -121,8 +122,10 @@ Route::prefix('internal')->group(function () {
|
||||
Route::resource('organizations', OrganizationController::class);
|
||||
Route::resource('doctors', DoctorController::class);
|
||||
|
||||
|
||||
Route::get('generate-log/{member_id}', [CorporateMemberController::class, 'generateLog']);
|
||||
|
||||
Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index');
|
||||
Route::post('claim-requests/{id}/approve', [ClaimRequestController::class, 'approve'])->name('claim-requests.approve');
|
||||
});
|
||||
|
||||
// Route::resource('organizations', OrganizationController::class);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
52
app/Models/ClaimRequest.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Blameable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class ClaimRequest extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes, Blameable;
|
||||
|
||||
protected static $code_prefix = 'CRQ';
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::creating(function ($model) {
|
||||
try {
|
||||
$model->code = self::getNextCode();
|
||||
} catch (\Exception $e) {
|
||||
abort(500, $e->getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 $fillable = [
|
||||
'submission_date',
|
||||
'member_id',
|
||||
'status'
|
||||
];
|
||||
|
||||
public function member()
|
||||
{
|
||||
return $this->belongsTo(Member::class, 'member_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -192,12 +192,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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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',
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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->string('code')->index();
|
||||
$table->dateTime('submission_date')->nullable();
|
||||
$table->foreignId('member_id');
|
||||
$table->string('status')->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_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']);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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>
|
||||
);
|
||||
}
|
||||
272
frontend/dashboard/src/pages/ClaimRequests/List.tsx
Executable file
@@ -0,0 +1,272 @@
|
||||
// @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 LoadingButton from '@/theme/overrides/LoadingButton';
|
||||
|
||||
export default function List() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
const navigate = useNavigate();
|
||||
|
||||
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="right"><Chip label={row.status}/></TableCell>
|
||||
<TableCell align="right">{ row.status == 'requested' && (<LoadingButton loading={loadingApprove} variant="outlined" onClick={() => {handleApprove(row)}}>Approve</LoadingButton> )}</TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ borderBottom: 1 }}>
|
||||
<Typography variant="body2" gutterBottom component="div">
|
||||
Description : {row.description}
|
||||
</Typography>
|
||||
</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">
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<ImportForm />
|
||||
|
||||
<DataTable
|
||||
isLoading={dataTableIsLoading}
|
||||
lastRequest={0}
|
||||
data={dataTableData}
|
||||
handlePageChange={handlePageChange}
|
||||
TableContent={<TableContent />}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -221,6 +221,10 @@ export default function Router() {
|
||||
path: 'claims',
|
||||
element: <Claims />,
|
||||
},
|
||||
{
|
||||
path: 'claim-requests',
|
||||
element: <ClaimRequests />,
|
||||
},
|
||||
{
|
||||
path: 'claims/create',
|
||||
element: <ClaimsCreate />,
|
||||
@@ -339,3 +343,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
@@ -0,0 +1,4 @@
|
||||
|
||||
REACT_APP_HOST_API_URL="http://localhost:8000"
|
||||
|
||||
VITE_API_URL="http://localhost:8000/api/hospitalportal"
|
||||
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 2
|
||||
}
|
||||
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
116
frontend/hospital-portal/package.json
Executable file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"name": "@minimal/material-kit-react",
|
||||
"author": "minimals.cc",
|
||||
"version": "3.2.0",
|
||||
"description": "Simple React Scripts & Typescript",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "eslint --ext .ts,.tsx ./src",
|
||||
"lint:fix": "eslint --fix --ext .ts,.tsx ./src",
|
||||
"start": "vite --port=3000",
|
||||
"build": "vite build --mode production && cp .htaccess build/.htaccess && rm -f -r @/public/dashboard && cp -r build @/public/dashboard",
|
||||
"build-staging": "vite build --mode staging && cp .htaccess build/.htaccess && rm -f -r @/public/dashboard-staging && cp -r build @/public/dashboard-staging",
|
||||
"serve": "vite preview",
|
||||
"clear-all": "rm -rf build node_modules",
|
||||
"re-start": "rm -rf build node_modules && yarn install && yarn start",
|
||||
"re-build": "rm -rf build node_modules && yarn install && yarn build"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app"
|
||||
]
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"@babel/preset-react"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@date-io/date-fns": "^2.16.0",
|
||||
"@emotion/cache": "^11.10.5",
|
||||
"@emotion/react": "^11.10.5",
|
||||
"@emotion/styled": "^11.10.5",
|
||||
"@hookform/resolvers": "^2.9.10",
|
||||
"@iconify/react": "^3.2.2",
|
||||
"@mui/icons-material": "^5.11.0",
|
||||
"@mui/lab": "5.0.0-alpha.80",
|
||||
"@mui/material": "^5.11.8",
|
||||
"@mui/system": "^5.11.7",
|
||||
"@mui/utils": "^5.11.7",
|
||||
"@mui/x-data-grid": "^5.17.21",
|
||||
"@mui/x-date-pickers": "5.0.0-beta.2",
|
||||
"@vitejs/plugin-react": "^1.3.2",
|
||||
"apexcharts": "^3.36.3",
|
||||
"axios": "^0.27.2",
|
||||
"change-case": "^4.1.2",
|
||||
"csstype": "^3.1.1",
|
||||
"date-fns": "^2.29.3",
|
||||
"framer-motion": "^6.5.1",
|
||||
"highlight.js": "^11.7.0",
|
||||
"history": "^5.3.0",
|
||||
"jsx-runtime": "^1.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"notistack": "3.0.0-alpha.11",
|
||||
"nprogress": "^0.2.0",
|
||||
"numeral": "^2.0.6",
|
||||
"react": "^17.0.2",
|
||||
"react-apexcharts": "^1.4.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-helmet-async": "^1.3.0",
|
||||
"react-hook-form": "^7.43.0",
|
||||
"react-intersection-observer": "^8.34.0",
|
||||
"react-lazy-load-image-component": "^1.5.6",
|
||||
"react-quill": "2.0.0-beta.4",
|
||||
"react-router": "^6.8.0",
|
||||
"react-router-dom": "^6.8.0",
|
||||
"simplebar": "^5.3.9",
|
||||
"simplebar-react": "^2.4.3",
|
||||
"stylis": "^4.1.3",
|
||||
"stylis-plugin-rtl": "^2.1.1",
|
||||
"vite": "^3.2.5",
|
||||
"vite-plugin-svgr": "^2.4.0",
|
||||
"yup": "^0.32.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-syntax-flow": "^7.18.6",
|
||||
"@babel/plugin-transform-react-jsx": "^7.20.13",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"@types/react": "^17.0.53",
|
||||
"@types/react-dom": "^17.0.18",
|
||||
"@types/react-lazy-load-image-component": "^1.5.2",
|
||||
"@types/stylis": "^4.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.50.0",
|
||||
"@typescript-eslint/parser": "^5.50.0",
|
||||
"eslint": "^8.33.0",
|
||||
"eslint-config-airbnb": "19.0.4",
|
||||
"eslint-config-airbnb-typescript": "^16.2.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-config-react-app": "7.0.0",
|
||||
"eslint-import-resolver-typescript": "^2.7.1",
|
||||
"eslint-plugin-flowtype": "^8.0.3",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jsx-a11y": "6.5.1",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "4.3.0",
|
||||
"prettier": "^2.8.3",
|
||||
"typescript": "^4.9.5",
|
||||
"vite-plugin-pwa": "^0.12.8"
|
||||
}
|
||||
}
|
||||
6194
frontend/hospital-portal/pnpm-lock.yaml
generated
Executable file
1
frontend/hospital-portal/public/_redirects
Executable file
@@ -0,0 +1 @@
|
||||
/* /index.html 200
|
||||
BIN
frontend/hospital-portal/public/favicon/android-chrome-192x192.png
Executable file
|
After Width: | Height: | Size: 14 KiB |
BIN
frontend/hospital-portal/public/favicon/android-chrome-512x512.png
Executable file
|
After Width: | Height: | Size: 43 KiB |
BIN
frontend/hospital-portal/public/favicon/apple-touch-icon.png
Executable file
|
After Width: | Height: | Size: 12 KiB |
BIN
frontend/hospital-portal/public/favicon/favicon-16x16.png
Executable file
|
After Width: | Height: | Size: 573 B |
BIN
frontend/hospital-portal/public/favicon/favicon-32x32.png
Executable file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
frontend/hospital-portal/public/favicon/favicon.ico
Executable file
|
After Width: | Height: | Size: 15 KiB |
BIN
frontend/hospital-portal/public/fonts/CircularStd-Bold.otf
Executable file
BIN
frontend/hospital-portal/public/fonts/CircularStd-Book.otf
Executable file
BIN
frontend/hospital-portal/public/fonts/CircularStd-Medium.otf
Executable file
BIN
frontend/hospital-portal/public/fonts/Roboto-Bold.ttf
Executable file
BIN
frontend/hospital-portal/public/fonts/Roboto-Regular.ttf
Executable file
18
frontend/hospital-portal/public/fonts/index.css
Executable file
@@ -0,0 +1,18 @@
|
||||
@font-face {
|
||||
font-family: 'CircularStd';
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
src: local('CircularStd'), url('CircularStd-Book.otf') format('opentype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'CircularStd';
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
src: local('CircularStd'), url('CircularStd-Medium.otf') format('opentype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'CircularStd';
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
src: local('CircularStd'), url('CircularStd-Bold.otf') format('opentype');
|
||||
}
|
||||
1
frontend/hospital-portal/public/icons/ic_analytics.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m20.247634 1c1.0125221 0 1.8333334.82081129 1.8333334 1.83333333s-.8208113 1.83333334-1.8333334 1.83333334c-.3158442 0-.6130339-.07986936-.8724738-.22051281l-3.0249251 3.47961717c.1346337.25513483.2108509.5458717.2108509.85441003 0 1.01252204-.8208113 1.83333334-1.8333334 1.83333334-.9820883 0-1.7838173-.7722101-1.8311257-1.74256896l-2.2033918-.75849737c-.336256.40778098-.84535009.66773299-1.41515923.66773299-.32712483 0-.63423886-.08567643-.90012689-.2358141l-2.87560465 2.41277624c.05416355.1730906.08335496.3572185.08335496.5481644 0 1.012522-.8208113 1.8333333-1.83333334 1.8333333s-1.83333333-.8208113-1.83333333-1.8333333c0-1.0125221.82081129-1.83333335 1.83333333-1.83333335.33090488 0 .64133381.08766791.90932763.24104456l2.86960725-2.40787374c-.05621505-.1760311-.0865583-.3636207-.0865583-.55829735 0-1.01252204.8208113-1.83333333 1.83333334-1.83333333.97577423 0 1.77350093.76231258 1.83011983 1.7238777l2.2160025.76325559c.336304-.39976002.8402621-.65379996 1.4035544-.65379996.2130474 0 .4176071.03634016.6078186.10315996l3.1693503-3.64581344c-.0588143-.17965899-.0906208-.37154554-.0906208-.57086091 0-1.01252204.8208113-1.83333333 1.8333333-1.83333333z" opacity=".48"/><path d="m21.1666667 9.60855714c.506261 0 .9166666.41040566.9166666.91666666v10.7540685c0 .2761423-.2238576.5-.5.5h-2.6666666c-.2761424 0-.5-.2238577-.5-.5v-10.7540685c0-.506261.4104056-.91666666.9166666-.91666666zm-5.5 6.42549146c.506261 0 .9166666.4104057.9166666.9166667v4.328577c0 .2761423-.2238576.5-.5.5h-2.6666666c-.2761424 0-.5-.2238577-.5-.5v-4.328577c0-.506261.4104056-.9166667.9166666-.9166667zm-5.5-1.8405511c.506261 0 .9166666.4104057.9166666.9166667v6.1691281c0 .2761423-.2238576.5-.5.5h-2.66666663c-.27614238 0-.5-.2238577-.5-.5v-6.1691281c0-.506261.41040564-.9166667.91666666-.9166667zm-5.50000003 4.7135227c.50626102 0 .91666666.4104057.91666666.9166667v1.4556054c0 .2761423-.22385762.5-.5.5h-2.66666666c-.27614238 0-.5-.2238577-.5-.5v-1.4556054c0-.506261.41040564-.9166667.91666666-.9166667z"/></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
5
frontend/hospital-portal/public/icons/ic_banking.svg
Executable file
@@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.5367 20.5812H2.45436C1.92714 20.5812 1.5 21.0083 1.5 21.536C1.5 22.0628 1.92714 22.4899 2.45436 22.4899H21.5362C22.0635 22.4899 22.4906 22.0628 22.4906 21.536C22.4902 21.0083 22.063 20.5812 21.5367 20.5812Z" fill="#637381"/>
|
||||
<path d="M3.64772 18.1001C3.1205 18.1001 2.69336 18.5273 2.69336 19.0545C2.69336 19.5817 3.1205 20.0093 3.64772 20.0093H20.3446C20.8718 20.0093 21.2989 19.5817 21.2989 19.0545C21.2989 18.5273 20.8718 18.1001 20.3446 18.1001H20.1064V9.51266H20.3446C20.6086 9.51266 20.8213 9.29909 20.8213 9.03592C20.8213 8.77276 20.6077 8.55919 20.3446 8.55919H3.64772C3.38411 8.55919 3.17099 8.77276 3.17099 9.03592C3.17099 9.29909 3.38456 9.51266 3.64772 9.51266H3.88631V18.0997H3.64772V18.1001ZM18.1977 9.51266V18.0997H15.3355V9.51266H18.1977ZM13.4268 9.51266V18.0997H10.5646V9.51266H13.4268ZM5.79414 9.51266H8.65633V18.0997H5.79414V9.51266Z" fill="#637381"/>
|
||||
<path opacity="0.48" d="M2.45438 7.70134H21.5363C21.5394 7.70134 21.543 7.70134 21.5456 7.70134C22.0733 7.70134 22.5 7.2742 22.5 6.74698C22.5 6.32788 22.2301 5.97268 21.8553 5.844L12.3876 1.58377C12.1387 1.47208 11.8541 1.47208 11.6048 1.58377L2.06298 5.87706C1.65238 6.06204 1.42674 6.50794 1.52146 6.94759C1.61574 7.38724 2.00445 7.70134 2.45438 7.70134Z" fill="#637381"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
frontend/hospital-portal/public/icons/ic_blog.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m14.984127 0c2.7619047 0 5.015873 2.25396825 5.015873 5.01587302v9.96825398c0 2.7619047-2.2539683 5.015873-5.015873 5.015873h-9.984127c-2.74603175 0-5-2.2539683-5-5v-9.98412698c0-2.76190477 2.25396825-5.01587302 5-5.01587302zm-4.5079365 3.80952381h-2.76190479c-2.17460317 0-3.9047619 1.73015873-3.9047619 3.88888889v4.6031746c0 2.1587302 1.73015873 3.8888889 3.9047619 3.8888889h4.53968259c2.1746031 0 3.9523809-1.7460318 3.9682539-3.9047619v-3.15873017l-.031746-.15873016-.1111111-.22222222-.1746032-.14285715c-.2380952-.17460317-1.3968254.01587302-1.7142857-.26984127-.2222222-.2063492-.2539683-.57142857-.3174603-1.06349206-.1111111-.96825397-.2063492-1.01587302-.3492064-1.33333333-.5396825-1.15873016-2.031746-2.12698413-3.047619-2.12698413zm1.7460317 7.61904759c.4126984 0 .7460318.3809524.7460318.7936508s-.3333334.7936508-.7460318.7936508h-4.46031744c-.42857143 0-.76190476-.3809524-.76190476-.7936508s.34920635-.7936508.76190476-.7936508zm-2.26984125-4.44444442c.42857145 0 .76190475.30158731.76190475.71428572s-.3492063.71428571-.76190475.71428571h-2.19047619c-.41269841 0-.76190476-.3015873-.76190476-.71428571s.34920635-.71428572.76190476-.71428572z" transform="translate(2 2)"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
frontend/hospital-portal/public/icons/ic_booking.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><g fill="#637381"><path d="m16.8125 2.83333h-1.1459v-.91667c0-.50599-.4097-.91666-.9166-.91666s-.9167.41067-.9167.91666v.91667h-7.33331v-.91667c0-.50599-.40975-.91666-.91667-.91666-.50691 0-.91666.41067-.91666.91666v.91667h-1.14583c-1.39058 0-2.52083 1.13025-2.52083 2.52083v10.31244c0 1.5162 1.23383 2.75 2.74999 2.75h4.58333c.50691 0 .91666-.4106.91666-.9166s-.40975-.9167-.91666-.9167h-4.58333c-.50599 0-.91666-.4116-.91666-.9167v-7.33328h14.66667c0 .506.4097.91666.9166.91666s.9167-.41066.9167-.91666v-2.97916c0-1.39058-1.1302-2.52083-2.5208-2.52083z"/><path d="m17.0413 11.0834c-3.2853 0-5.9583 2.673-5.9583 5.9583s2.673 5.9583 5.9583 5.9583 5.9583-2.673 5.9583-5.9583-2.673-5.9583-5.9583-5.9583zm2.7555 4.9545-2.9791 3.4375c-.1669.1925-.4061.3062-.66.3163-.011 0-.022 0-.033 0-.243 0-.4758-.0963-.6481-.2686l-1.6042-1.6042c-.3584-.3584-.3584-.9377 0-1.2961.3584-.3585.9378-.3585 1.2962 0l.9084.9084 2.3338-2.6932c.3318-.3831.9112-.4226 1.2934-.0926.3823.331.4235.9103.0926 1.2925z" opacity=".48"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
1
frontend/hospital-portal/public/icons/ic_calendar.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><g transform="translate(1.5 1.5)"><path d="m18.9 3.15h-16.8c-1.15931815.00115758-2.09884242.94068185-2.1 2.1v12.95c.00115758 1.1593181.94068185 2.0988424 2.1 2.1h16.8c1.1593181-.0011576 2.0988424-.9406819 2.1-2.1v-12.95c-.0011576-1.15931815-.9406819-2.09884242-2.1-2.1zm0 16.45h-16.8c-.77319865 0-1.4-.6268014-1.4-1.4v-10.5h19.6v10.5c0 .7731986-.6268014 1.4-1.4 1.4zm-2.45-17.15v-1.75c0-.38659932-.3134007-.7-.7-.7s-.7.31340068-.7.7v1.75zm-10.5 0v-1.75c0-.38659932-.31340068-.7-.7-.7s-.7.31340068-.7.7v1.75z"/><path d="m5.99840724 14.441644c.55228475 0 1 .4477153 1 1v1.6c0 .5522848-.44771525 1-1 1h-2.2c-.55228475 0-1-.4477152-1-1v-1.6c0-.5522847.44771525-1 1-1zm5.60159276 0c.5522847 0 1 .4477153 1 1v1.6c0 .5522848-.4477153 1-1 1h-2.2c-.55228475 0-1-.4477152-1-1v-1.6c0-.5522847.44771525-1 1-1zm-5.60159276-5.0001284c.55228475 0 1 .44771525 1 1v1.6c0 .5522848-.44771525 1-1 1h-2.2c-.55228475 0-1-.4477152-1-1v-1.6c0-.55228475.44771525-1 1-1zm5.60159276 0c.5522847 0 1 .44771525 1 1v1.6c0 .5522848-.4477153 1-1 1h-2.2c-.55228475 0-1-.4477152-1-1v-1.6c0-.55228475.44771525-1 1-1zm5.6015928 0c.5522847 0 1 .44771525 1 1v1.6c0 .5522848-.4477153 1-1 1h-2.2c-.5522848 0-1-.4477152-1-1v-1.6c0-.55228475.4477152-1 1-1z" opacity=".48"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
frontend/hospital-portal/public/icons/ic_cart.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><g transform="translate(2 2)"><path d="m9.58985382 1.32162476c1.66180188 0 3.06430158 1.12239456 3.49720258 2.64777104h-6.99440518c.432901-1.52537648 1.83540001-2.64777104 3.4972026-2.64777104zm4.62891648-1.32162476c.9093636 0 1.6555835.7429914 1.6555835 1.65235392 0 .90937489-.7462199 1.6529999-1.6555835 1.6529999-.909364 0-1.6529999-.74362501-1.6529999-1.6529999 0-.90936252.7436359-1.65235392 1.6529999-1.65235392z" opacity=".48"/><path d="m7.60483293 15.8737079c.90936397 0 1.6529999.7436373 1.6529999 1.6529999 0 .9093749-.74362997 1.6549376-1.6529999 1.6549376s-1.65235399-.7455627-1.65235399-1.6549376c0-.9093626.74299001-1.6529999 1.65235399-1.6529999zm6.61393737 0c.9093636 0 1.6555835.7436373 1.6555835 1.6529999 0 .9093749-.7462136 1.6549376-1.6555835 1.6549376-.90937 0-1.6529999-.7455627-1.6529999-1.6549376 0-.9093626.7436349-1.6529999 1.6529999-1.6529999zm-10.58074958-13.22722875c.47021948.00126272.87961059.33725114.97151692.79840103l.23706567 1.18597394h13.34220869c.6357812 0 1.1062464.60903974.9644116 1.2234396l-1.9850212 8.59895818c-.1036535.4490251-.5105252.7589977-.9644112.7589977h-10.58333325c-.47083827 0-.88484536-.3341221-.97216282-.8009847l-1.82805386-9.78234852h-1.82869973c-.30322176 0-.57131938-.12557224-.74220274-.31781022-.17088343-.19224988-.2493388-.43483146-.2493388-.67373135 0-.2388999.07845541-.48148147.2493388-.67373136.17088336-.19223764.43898098-.3171643.74220274-.3171643z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
1
frontend/hospital-portal/public/icons/ic_chat.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><g transform="translate(.5 2.5)"><path d="m8.3418125.28845833c-4.72554167 0-8.3418125 3.20658334-8.3418125 6.70210417 0 3.4955208 3.12225 5.5209583 3.12225 5.5209583l-.5074375 1.923375c-.06708333.2534792.20460417.462875.4326875.3335l2.28083333-1.2923125c1.00864584.3210417 3.14908334.4235834 3.35752084.4331667-.1495-.5184583-.22329167-1.02925-.22329167-1.5060208 0-2.69770837 2.348875-6.49750003 7.5703542-6.49750003.1188333 0 .2376666.002875.3565.00766666-.6947917-3.32541666-4.1476667-5.6249375-8.0476042-5.6249375z"/><path d="m23 11.9810833c0-3.06187497-3.5923125-5.3038958-6.9675625-5.3038958-4.7734583 0-6.79889583 3.4476042-6.79889583 5.7260417 0 2.2832291 2.02495833 5.7260416 6.79889583 5.7260416 1.0560833 0 1.9851875-.1514166 2.7930625-.41975l1.7954375 1.1394584c.1418333.0900833.3210417-.0368959.2831875-.2007709l-.4072917-1.768125c1.69625-1.181625 2.5031667-3.0441458 2.5031667-4.899z" opacity=".48"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1007 B |
1
frontend/hospital-portal/public/icons/ic_dashboard.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><g transform="translate(2 4)"><path d="m18.38 4.57-1.23 1.85c1.2049 2.40314304 1.1222508 5.2507848-.22 7.58h-13.86c-1.76350331-3.059309-1.31261601-6.91298595 1.10947843-9.48257235s6.24242627-3.24722187 9.40052157-1.66742765l1.85-1.23c-3.8761922-2.48556317-8.94860517-2.00294347-12.28650726 1.16901179-3.3379021 3.17195526-4.07833512 8.21319061-1.79349274 12.21098821.35510459.6150891 1.00977788.9957131 1.72 1.0000158h13.85c.7173695.0028322 1.3813181-.3787474 1.74-1.0000158 1.8786438-3.25433 1.7743473-7.28712667-.27-10.44z"/><path d="m8.59 11.41c.37513651.3755541.8841815.5865733 1.415.5865733s1.0398635-.2110192 1.415-.5865733l5.66-8.49-8.49 5.66c-.37555409.37513651-.58657331.8841815-.58657331 1.415s.21101922 1.0398635.58657331 1.415z" opacity=".48"/></g></svg>
|
||||
|
After Width: | Height: | Size: 849 B |
1
frontend/hospital-portal/public/icons/ic_ecommerce.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m7.94101676 5.6427832v2.74464258c0 .33989649.27513281.6150293.6150293.6150293.30862393 0 .56440212-.22738249.60835663-.52409402l.00667266-.09093528v-2.74464258h5.65814645v2.74464258c0 .33989649.275543.6150293.6150293.6150293.3089968 0 .5644699-.22738249.6083659-.52409402l.0066634-.09093528v-2.74464258h1.8524297c.7157099 0 1.3265895.52397061 1.44811 1.21681899l.0176654.14071617.9376992 11.81697074c.0730078.9483222-.2554043 1.8905332-.900334 2.5867324-.5953575.6426454-1.4202201 1.03272-2.2901578 1.0889289l-.2183168.0070496h-9.81241403c-.94918359 0-1.8635039-.3997793-2.50847461-1.0959375-.59531971-.6426454-.92094397-1.4949103-.91044964-2.3668484l.00966449-.2182844.93810937-11.82025197c.0545636-.71224914.62412163-1.28073532 1.3241451-1.34901387l.14163029-.00688066zm4.09817114 3.97089698c-.2266736-.00327725-.4135824.17768425-.4169046.40501402v.7555922c-1.4912918.1060463-2.50536524 1.0273421-2.50536524 2.253508 0 1.5045398 1.27919924 1.9221212 2.50536524 2.253508v2.6511967c-.6469005-.0868303-1.2566612-.3552579-1.7564176-.7754643-.09411064-.0748948-.21077995-.1166488-.33140728-.1192943-.30554685.0212051-.54083371.2770409-.5369249.5832645-.00060704.1338754.05174957.2624598.14586021.3579034.68467596.6164053 1.56487397.9710069 2.48549307 1.0008254l.0006563.7430004c.0106025.2266735.2034791.4016467.4301527.3903879.2233717 0 .4043127-.180941.4043127-.4043128v-.7423236c1.8094305-.1192943 2.538506-1.2195419 2.538506-2.3860709 0-1.5642177-1.3122785-2.041436-2.5384649-2.3728433v-2.3330375c.4990796.0841848.9696739.2889765 1.3719974.5965126.0802063.0550021.1743169.0848411.2717499.0861536.3121708 0 .5666941-.251201.5699959-.5633719.0006562-.1338754-.0517004-.2624598-.145811-.3579035-.5812753-.4977671-1.3103508-.7913784-2.0745563-.8351217v-.7821089c0-.22337175-.180941-.40431274-.4043128-.40431274-.0046347-.00070128-.00929-.00070128-.0139248-.00070128zm.4248617 5.91949992c.7489681.2120925 1.3322121.4970904 1.3255881 1.1930252 0 .503735-.3446554 1.1002476-1.3255881 1.2195419zm-.8351218-3.7050349v2.1673339c-.7224514-.2120925-1.2858233-.430809-1.2858233-1.0472142 0-.6164053.510359-1.0604828 1.2858233-1.1201197zm.3712413-10.3281452c2.2382637 0 4.0591523 1.82125781 4.0591523 4.05952148v.08322071h-1.2300175v-.08322071c0-1.56011132-1.2689825-2.8295039-2.8290938-2.8295039s-2.82909373 1.26939258-2.82909373 2.8295039v.08322071h-1.23005859v-.08322071c0-2.23826367 1.82084765-4.05952148 4.05911132-4.05952148z"/></svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
8
frontend/hospital-portal/public/icons/ic_kanban.svg
Executable file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>ic_kanban</title>
|
||||
<g id="ic_kanban" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M20,3 C21.1045695,3 22,3.8954305 22,5 L22,15 C22,16.1045695 21.1045695,17 20,17 L4,17 C2.8954305,17 2,16.1045695 2,15 L2,5 C2,3.8954305 2.8954305,3 4,3 L20,3 Z M11.5,6 L6.5,6 C5.67157288,6 5,6.67157288 5,7.5 L5,7.5 L5,9.5 C5,10.3284271 5.67157288,11 6.5,11 L6.5,11 L11.5,11 C12.3284271,11 13,10.3284271 13,9.5 L13,9.5 L13,7.5 C13,6.67157288 12.3284271,6 11.5,6 L11.5,6 Z" id="Combined-Shape" fill="#000000"></path>
|
||||
<path d="M8,21 L16,21 M12,17 L12,21" id="Combined-Shape" stroke="#000000" stroke-width="2" opacity="0.48" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 915 B |
1
frontend/hospital-portal/public/icons/ic_mail.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><g transform="translate(1.5 4)"><path d="m11.0988387 10.3846452c-.1981935.1238709-.4211613.1734193-.6193548.1734193-.1981936 0-.4211613-.0495484-.61935487-.1734193l-9.86012903-6.02012907v8.00206447c0 1.7094194 1.38735484 3.0967742 3.09677419 3.0967742h14.79019351c1.7094194 0 3.0967742-1.3873548 3.0967742-3.0967742v-8.00206447z"/><path d="m17.8869677.00425806h-14.79019351c-1.46167742 0-2.70038709 1.04051613-2.99767742 2.42787097l10.40516133 6.34219355 10.3803871-6.34219355c-.2972904-1.38735484-1.536-2.42787097-2.9976775-2.42787097z" opacity=".48"/></g></svg>
|
||||
|
After Width: | Height: | Size: 646 B |
1
frontend/hospital-portal/public/icons/ic_user.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><g transform="translate(5 3)"><path d="m7 8c2.209139 0 4-1.790861 4-4s-1.790861-4-4-4-4 1.790861-4 4 1.790861 4 4 4z" opacity=".48"/><path d="m13 18.0000001c.5522847 0 1-.4477154 1-1 0-3.8659933-3.1340068-7-7-7-3.86599321 0-7 3.1340067-7 7 0 .5522846.44771525 1 1 1z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 362 B |
BIN
frontend/hospital-portal/public/image/overlay.png
Normal file
|
After Width: | Height: | Size: 473 KiB |
BIN
frontend/hospital-portal/public/logo/logo-linksehat.png
Executable file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
frontend/hospital-portal/public/logo/logo_full.jpg
Executable file
|
After Width: | Height: | Size: 21 KiB |
1
frontend/hospital-portal/public/logo/logo_full.svg
Executable file
|
After Width: | Height: | Size: 4.9 KiB |
1
frontend/hospital-portal/public/logo/logo_single.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg height="512" viewBox="0 0 512 512" width="512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" x1="100%" x2="50%" y1="5.663%" y2="50%"><stop offset="0" stop-color="#007b55"/><stop offset="1" stop-color="#00ab55"/></linearGradient><linearGradient id="b" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0" stop-color="#5be584"/><stop offset="1" stop-color="#00ab55"/></linearGradient><g fill="none" fill-rule="evenodd" transform="translate(14 128)"><path d="m92.8065878 83.1065019c44.2888442 22.8889511 46.3079382 23.9345951 46.4006692 23.9799821.012248.008728.642121.333419 44.792743 23.152545-26.071507 48.53952-42.693165 77.265922-49.868472 86.179207-10.758587 13.369926-22.495227 23.492946-36.929824 29.333888-30.3458978 14.261953-68.070062 14.928791-97.201704-2.704011z" fill="url(#a)"/><g fill="url(#b)"><path d="m430.310491 101.726093c-46.270793-80.9559274-94.100378-157.2284394-149.043472-45.3437359-7.516227 14.3833977-12.994566 42.3366008-25.267019 42.3366008v-.1420279c-12.272453 0-17.749057-27.9532032-25.265283-42.3366009-54.94483-111.8847034-102.774415-35.6121915-149.0452076 45.3437359-3.4821132 6.105448-6.8270943 11.9321-9.6895094 16.99601 106.037811-67.1266136 97.11034 135.666494 184 137.277897v.142028c86.891396-1.611403 77.962189-204.4045106 184-137.27965-2.860679-5.062157-6.20566-10.888809-9.689509-16.994257"/><path d="m436 256c26.5088 0 48-21.4912 48-48s-21.4912-48-48-48-48 21.4912-48 48 21.4912 48 48 48"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
20
frontend/hospital-portal/public/manifest.json
Executable file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "React Material Minimal UI",
|
||||
"short_name": "Minimal-UI",
|
||||
"display": "standalone",
|
||||
"start_url": "/",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "favicon/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
3
frontend/hospital-portal/public/robots.txt
Executable file
@@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||