Merge remote-tracking branch 'origin/staging' into origin/production
This commit is contained in:
@@ -135,7 +135,7 @@ class DrugController extends Controller
|
||||
]);
|
||||
}
|
||||
}
|
||||
public function downloadTemplate()
|
||||
public function downloadTemplate()
|
||||
{
|
||||
return Helper::responseJson([
|
||||
'file_name' => "Template - Drugs.xlsx",
|
||||
@@ -149,7 +149,6 @@ class DrugController extends Controller
|
||||
$data = Excel::toArray([], $file);
|
||||
|
||||
$processedData = $this->processCategoryNames($data);
|
||||
|
||||
$importedRows = 0;
|
||||
$failedRows = [];
|
||||
|
||||
@@ -170,6 +169,7 @@ class DrugController extends Controller
|
||||
'type' => $row['type'],
|
||||
'dosage' => $row['dosage'],
|
||||
'remark' => $row['remark'],
|
||||
'price' => $row['price'],
|
||||
]
|
||||
);
|
||||
$importedRows++;
|
||||
@@ -201,7 +201,7 @@ class DrugController extends Controller
|
||||
$row[] = $data[0][$i];
|
||||
$header[] = $data[0][0];
|
||||
}
|
||||
|
||||
|
||||
$filed = [];
|
||||
foreach ($header[0] as $value)
|
||||
{
|
||||
@@ -212,16 +212,16 @@ class DrugController extends Controller
|
||||
$filed[] = $modelColumn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$result = [];
|
||||
foreach ($row as $subarray) {
|
||||
$trimmedSubarray = [];
|
||||
for ($i = 0; $i < count($filed); $i++) {
|
||||
$trimmedSubarray[$filed[$i]] = $subarray[$i] ? $subarray[$i] : null;
|
||||
}
|
||||
|
||||
|
||||
$result[] = $trimmedSubarray;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
125
Modules/Internal/Http/Controllers/Api/NavigationController.php
Normal file
125
Modules/Internal/Http/Controllers/Api/NavigationController.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Internal\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Navigations;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
|
||||
class NavigationController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
// Ambil semua navigasi dari tabel dan ubah menjadi array
|
||||
$navigations = Navigations::all()->toArray();
|
||||
$navigationMaster = [];
|
||||
|
||||
if ($navigations) {
|
||||
// Buat array untuk menyimpan menu utama
|
||||
foreach ($navigations as $navigation) {
|
||||
if ($navigation['parent_id'] == 0) {
|
||||
// Tambahkan menu utama ke $navigationMaster
|
||||
$navigation['children'] = []; // Siapkan array untuk children
|
||||
$navigationMaster[$navigation['id']] = $navigation;
|
||||
}
|
||||
}
|
||||
|
||||
// Tambahkan submenu ke menu utama yang sesuai
|
||||
foreach ($navigations as $navigation) {
|
||||
if ($navigation['parent_id'] != 0 && isset($navigationMaster[$navigation['parent_id']])) {
|
||||
$navigationMaster[$navigation['parent_id']]['children'][] = $navigation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ubah array menjadi list tanpa indeks id
|
||||
$navigationMaster = array_values($navigationMaster);
|
||||
|
||||
// Transformasi data untuk sesuai dengan format yang diinginkan
|
||||
$formattedNavigation = [
|
||||
'items' => array_map(function ($navItem) {
|
||||
return [
|
||||
'title' => $navItem['title'],
|
||||
'path' => $navItem['path'],
|
||||
'children' => array_map(function ($child) {
|
||||
return [
|
||||
'title' => $child['title'],
|
||||
'path' => $child['path'],
|
||||
'icon' => $child['icon'], // Asumsikan Anda memiliki field 'icon' di tabel navigasi
|
||||
'permission' => $child['permission'],
|
||||
];
|
||||
}, $navItem['children']),
|
||||
'permission' => $navItem['permission'],
|
||||
];
|
||||
}, $navigationMaster)
|
||||
];
|
||||
|
||||
return response()->json($formattedNavigation);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -135,6 +135,7 @@ class PrescriptionController extends Controller
|
||||
'sKodeResep' => $kodeResep,
|
||||
'sDiagnose' => $sDiagnosis,
|
||||
'sKodeRS' => $hospital,
|
||||
'sStatus' => 1, // bayar'
|
||||
];
|
||||
|
||||
$prescription = Prescription::updateOrCreate([
|
||||
@@ -164,9 +165,11 @@ class PrescriptionController extends Controller
|
||||
$drugData = Drug::where('id', $value['drug_id'])->first();
|
||||
$drug = '';
|
||||
$drugCode = '';
|
||||
$drugPrice = 0;
|
||||
if ($drugData){
|
||||
$drug = $drugData->name;
|
||||
$drugCode = $drugData->code;
|
||||
$drugPrice = $drugData->price;
|
||||
}
|
||||
$unitData = Unit::where('id', $value['unit_id'])->first();
|
||||
$unit = '';
|
||||
@@ -192,6 +195,7 @@ class PrescriptionController extends Controller
|
||||
'sSatuan' => $unit,
|
||||
'sSigna' => $value['signa'],
|
||||
'sNote' => $value['note'],
|
||||
'nHarga' => $drugPrice
|
||||
];
|
||||
try {
|
||||
// Insert to ASO
|
||||
|
||||
@@ -6,12 +6,159 @@ use App\Helpers\Helper;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use App\Models\User;
|
||||
use App\Models\Person;
|
||||
use Crypt;
|
||||
|
||||
class UserManagemet extends Controller
|
||||
class UserManagementController extends Controller
|
||||
{
|
||||
public function index(Request $request){
|
||||
$user = User::all();
|
||||
return Helper::responseJson(data: $user);
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = Role::query();
|
||||
if ($request->has('search')) {
|
||||
$search = $request->get('search');
|
||||
$query->where('name', 'like', "%{$search}%");
|
||||
}
|
||||
$userRole = $query->paginate(10);
|
||||
return Helper::paginateResources($userRole);
|
||||
}
|
||||
}
|
||||
|
||||
public function permission_list(Request $request)
|
||||
{
|
||||
$permissions = Permission::all();
|
||||
return response()->json($permissions);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'guard_name' => 'required|string|max:255', // Pastikan setiap permission ada di tabel permissions
|
||||
]);
|
||||
|
||||
$newRole = Role::create([
|
||||
'name' => $validated['name'],
|
||||
'guard_name' => $validated['guard_name'],
|
||||
]);
|
||||
|
||||
if (isset($request->permission_check)) {
|
||||
$newRole->syncPermissions($request->permission_check);
|
||||
}
|
||||
|
||||
return response()->json($newRole, 201);
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$role = Role::with('permissions')->findOrFail($id);
|
||||
return response()->json($role);
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$role = Role::with('permissions')->findOrFail($id);
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'guard_name' => 'required|string|max:255',
|
||||
'permission_check' => 'nullable|array',
|
||||
'permission_check.*' => 'exists:permissions,id', // Pastikan setiap permission ada di tabel permissions
|
||||
]);
|
||||
|
||||
$role->update([
|
||||
'name' => $validated['name'],
|
||||
'guard_name' => $validated['guard_name'],
|
||||
]);
|
||||
|
||||
if (isset($validated['permission_check'])) {
|
||||
|
||||
$permissions = Permission::whereIn('id', $validated['permission_check'])
|
||||
->where('guard_name', $validated['guard_name'])
|
||||
->get();
|
||||
if ($permissions->count() !== count($validated['permission_check'])) {
|
||||
return response()->json(['error' => 'One or more permissions are invalid for the specified guard.'], 422);
|
||||
}
|
||||
$role->syncPermissions($permissions);
|
||||
}
|
||||
|
||||
return response()->json($role);
|
||||
}
|
||||
|
||||
public function list_role(Request $request)
|
||||
{
|
||||
$query = Role::all();
|
||||
$data = [
|
||||
'data' => $query
|
||||
];
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
public function store_access(Request $request){
|
||||
$user = User::create([
|
||||
'email' => $request->email,
|
||||
'username' => $request->username,
|
||||
'role_id' => $request->roles,
|
||||
'password' => Hash::make($request->password),
|
||||
]);
|
||||
|
||||
$person = Person::updateOrCreate(
|
||||
[
|
||||
'id' => $user->person_id
|
||||
],
|
||||
[
|
||||
'name' => $request->name ?? null
|
||||
]
|
||||
);
|
||||
$user->person_id = $person->id;
|
||||
$user->save();
|
||||
return response()->json($user);
|
||||
}
|
||||
|
||||
// List Access
|
||||
public function list_access(Request $request){
|
||||
$userAccess = User::query();
|
||||
if ($request->has('search')) {
|
||||
$search = $request->get('search');
|
||||
$userAccess->where('name', 'like', "%{$search}%");
|
||||
}
|
||||
$userAccess = $userAccess->paginate(10);
|
||||
return Helper::paginateResources($userAccess);
|
||||
}
|
||||
|
||||
public function edit_access($id){
|
||||
$userAccess = User::findOrFail($id);
|
||||
return response()->json($userAccess);
|
||||
}
|
||||
|
||||
public function update_access(Request $request, $id){
|
||||
$userAccess = User::findOrFail($id);
|
||||
|
||||
if (!$userAccess) {
|
||||
return response()->json(['error' => 'User Not found.'], 404);
|
||||
}
|
||||
|
||||
$userAccess->email = $request->email;
|
||||
$userAccess->username = $request->username;
|
||||
$userAccess->role_id = $request->roles;
|
||||
|
||||
if ($request->password){
|
||||
$userAccess->password = Hash::make($request->password);
|
||||
}
|
||||
|
||||
$person = Person::updateOrCreate(
|
||||
[
|
||||
'id' => $userAccess->person_id
|
||||
],
|
||||
[
|
||||
'name' => $request->name ?? null
|
||||
]
|
||||
);
|
||||
|
||||
$userAccess->person_id = $person->id;
|
||||
$userAccess->save();
|
||||
|
||||
return response()->json($userAccess);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,12 @@ use Modules\Internal\Http\Controllers\Api\ServiceController;
|
||||
use Modules\Internal\Http\Controllers\Api\PrescriptionController;
|
||||
use Modules\Internal\Http\Controllers\Api\SpecialityController;
|
||||
use Modules\Internal\Http\Controllers\Api\VillageController;
|
||||
use Modules\Internal\Http\Controllers\Api\NavigationController;
|
||||
use Modules\Internal\Http\Controllers\Api\AuditTrailController;
|
||||
use Modules\Internal\Http\Controllers\Api\DailyMonitoringController;
|
||||
use Modules\Internal\Http\Controllers\Api\LaboratoriumResultController;
|
||||
use Modules\Internal\Http\Controllers\Api\CorporateManageController;
|
||||
use Modules\Internal\Http\Controllers\Api\UserManagementController;
|
||||
use Modules\Internal\Http\Controllers\ClaimEncounterController;
|
||||
|
||||
// Report
|
||||
@@ -70,6 +72,10 @@ Route::prefix('internal')->group(function () {
|
||||
|
||||
Route::get('linksehat/payments', [PaymentController::class, 'index']);
|
||||
Route::get('linksehat/payments/generate-excel', [PaymentController::class, 'generateExcel']);
|
||||
Route::get('diagnosis', [RequestLogController::class, 'diagnosis']);
|
||||
Route::get('drugs', [DrugController::class, 'drugList']);
|
||||
Route::get('units', [DrugController::class, 'unitList']);
|
||||
|
||||
|
||||
|
||||
Route::middleware('auth:sanctum')->group(function () {
|
||||
@@ -288,11 +294,10 @@ Route::prefix('internal')->group(function () {
|
||||
Route::post('customer-service/request/final-log', [RequestLogController::class, 'updateFinalLog']);
|
||||
|
||||
// search diagnosis
|
||||
Route::get('diagnosis', [RequestLogController::class, 'diagnosis']);
|
||||
|
||||
// Route::get('diagnosis', [RequestLogController::class, 'diagnosis']);
|
||||
Route::get('hospitals', [RequestLogController::class, 'hospitals']);
|
||||
Route::get('drugs', [DrugController::class, 'drugList']);
|
||||
Route::get('units', [DrugController::class, 'unitList']);
|
||||
// Route::get('drugs', [DrugController::class, 'drugList']);
|
||||
// Route::get('units', [DrugController::class, 'unitList']);
|
||||
|
||||
// insert benefit
|
||||
Route::post('customer-service/request/insert-benefit', [RequestLogBenefitController::class, 'store']);
|
||||
@@ -355,6 +360,23 @@ Route::prefix('internal')->group(function () {
|
||||
});
|
||||
});
|
||||
|
||||
// User Management Role
|
||||
Route::get('user/role', [UserManagementController::class, 'index']);
|
||||
Route::post('user/role', [UserManagementController::class, 'store']);
|
||||
Route::get('user/role/{id}', [UserManagementController::class, 'edit']);
|
||||
Route::put('user/role/{id}', [UserManagementController::class, 'update']);
|
||||
Route::get('permission_list', [UserManagementController::class, 'permission_list']);
|
||||
|
||||
// User Role Access
|
||||
Route::get('user/access', [UserManagementController::class, 'list_access']);
|
||||
Route::post('user/access', [UserManagementController::class, 'store_access']);
|
||||
Route::get('user/access/{id}', [UserManagementController::class, 'edit_access']);
|
||||
Route::put('user/access/{id}', [UserManagementController::class, 'update_access']);
|
||||
Route::get('role-list', [UserManagementController::class, 'list_role']);
|
||||
|
||||
// Navigation
|
||||
Route::get('navigations', [NavigationController::class, 'index']);
|
||||
|
||||
});
|
||||
|
||||
Route::get('province', [ProvinceController::class, 'index']);
|
||||
|
||||
@@ -10,6 +10,9 @@ use App\Models\Message;
|
||||
use App\Models\File;
|
||||
use App\Models\Livechat;
|
||||
use App\Models\Person;
|
||||
use App\Models\Prescription;
|
||||
use App\Models\PrescriptionItem;
|
||||
use App\Models\Drug;
|
||||
use App\Models\OLDLMS\User;
|
||||
use App\Models\OLDLMS\UserDetail;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -34,7 +37,8 @@ class ChatController extends Controller
|
||||
|
||||
// Buat dan simpan data channel ke dalam tabel
|
||||
$channel = Channel::updateOrCreate([
|
||||
'name' => $request->member_id .'_' . $request->doctor_id,
|
||||
'member_id' => $request->member_id,
|
||||
'doctor_id' => $request->doctor_id,
|
||||
],
|
||||
[
|
||||
'name' => $request->member_id .'_' . $request->doctor_id,
|
||||
@@ -91,6 +95,7 @@ class ChatController extends Controller
|
||||
$arr['avatar'] = $avatarMember;
|
||||
$arr['name'] = $user->sFirstName .' '.$user->sLastName;
|
||||
$arr['last_message'] = $lastMessage;
|
||||
$arr['channel_id'] = $d['id'];
|
||||
|
||||
array_push($data, $arr);
|
||||
}
|
||||
@@ -232,8 +237,6 @@ class ChatController extends Controller
|
||||
if($address){
|
||||
$address = $address->sAlamat;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Ini Untul Chat
|
||||
@@ -257,6 +260,19 @@ class ChatController extends Controller
|
||||
if ($livechat->health_certificate_start && $livechat->health_certificate_end){
|
||||
$healthSertificate = True;
|
||||
}
|
||||
|
||||
$prescription = Prescription::where('livechat_id', $livechat->id)->first();
|
||||
$prescriptionItems = PrescriptionItem::with('drug')->where('prescription_id',$prescription->id)->get();
|
||||
$prescriptions = [];
|
||||
if ($prescriptionItems){
|
||||
foreach($prescriptionItems as $item){
|
||||
$row['medicine'] = $item->drug->name;
|
||||
$row['direction'] = $item->direction;
|
||||
$row['signa'] = $item->signa;
|
||||
$row['note'] = $item->note;
|
||||
array_push($prescriptions, $row);
|
||||
}
|
||||
}
|
||||
// Berikan respons yang sesuai ke klien
|
||||
return response()->json([
|
||||
'message' => 'Message sent successfully',
|
||||
@@ -290,6 +306,7 @@ class ChatController extends Controller
|
||||
'to' => $data->lastItem(),
|
||||
],
|
||||
'summary' => $consultationSummary,
|
||||
'prescription' => $prescriptions
|
||||
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -67,7 +67,8 @@ class AuthDoctorController extends Controller
|
||||
|
||||
$res_data = [
|
||||
// 'user' => $user,
|
||||
'token' => $user->createToken('app')->plainTextToken
|
||||
'token' => $user->createToken('app')->plainTextToken,
|
||||
'id' => $user->person->id
|
||||
];
|
||||
|
||||
return ApiResponse::apiResponse("Success", $res_data, trans('Message.success'), 200);
|
||||
|
||||
@@ -26,6 +26,7 @@ use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Kreait\Firebase\Messaging\CloudMessage;
|
||||
use Kreait\Laravel\Firebase\Facades\Firebase;
|
||||
use App\Events\ChatMessageSent;
|
||||
|
||||
class ChatDoctorController extends Controller
|
||||
{
|
||||
@@ -47,6 +48,7 @@ class ChatDoctorController extends Controller
|
||||
if($chat) {
|
||||
foreach($chat as $c){
|
||||
$patient = UserLMS::where('nID',$c->patient_id)->with('detail')->first();
|
||||
$channel = Channel::where(['doctor_id'=> $c->doctor_id, 'member_id' => $c->patient_id])->first();
|
||||
if ( $patient->detail) {
|
||||
$urlAvatarDefault = $patient->detail->nIDJenisKelamin == 1 ? 'https://linksehat.dev/assets/img/users/male-avatar.png' : 'https://linksehat.dev/assets/img/users/female-avatar.png';
|
||||
$avatarMember = $patient->detail->sImage ?? $urlAvatarDefault;
|
||||
@@ -56,14 +58,19 @@ class ChatDoctorController extends Controller
|
||||
$arr['id'] = $c->id;
|
||||
$arr['patient_id'] = $patient->nID;
|
||||
$arr['avatar'] = $avatarMember;
|
||||
$arr['name'] = $patient->sFirstName .' '.$patient->sLastName; ;
|
||||
$arr['name'] = $patient->sFirstName .' '.$patient->sLastName;
|
||||
$arr['channel_id'] = $channel->id;
|
||||
array_push($dataIncomingChat, $arr);
|
||||
}
|
||||
}
|
||||
|
||||
$dataChannel = Channel::where('doctor_id',$user->person_id)->get()->toArray();
|
||||
$dataOnGoing = [];
|
||||
if ($dataChannel){
|
||||
$chatOngoing = Livechat::where([
|
||||
'doctor_id'=> $user->person_id,
|
||||
'status' => 5
|
||||
])->get()->first();
|
||||
if ($chatOngoing && $dataChannel){
|
||||
foreach($dataChannel as $d){
|
||||
$user = UserLMS::with('detail')->where('nID', $d['member_id'])->first();
|
||||
$lastMessage = Message::where('channel_id', $d['id'])
|
||||
@@ -80,6 +87,7 @@ class ChatDoctorController extends Controller
|
||||
$arr['avatar'] = $avatarMember;
|
||||
$arr['name'] = $user->sFirstName .' '.$user->sLastName;
|
||||
$arr['last_message'] = $lastMessage;
|
||||
$arr['channel_id'] = $d['id'];
|
||||
|
||||
array_push($dataOnGoing, $arr);
|
||||
}
|
||||
@@ -145,13 +153,16 @@ class ChatDoctorController extends Controller
|
||||
'doctor_id' => $livechat->doctor_id
|
||||
])->first();
|
||||
$dataNotif = [
|
||||
'channel_id' => $channel->id,
|
||||
'livechat_id' => $livechat->id,
|
||||
'channel_id' => (string) $channel->id,
|
||||
'livechat_id' => (string) $livechat->id,
|
||||
'type' => 'decline-chat'
|
||||
];
|
||||
|
||||
$user = UserLMS::where('nID',$livechat->patient_id)->first();
|
||||
if ($user) {
|
||||
if ($user->nIDUser) { // Jika Dependent yang request
|
||||
$user = UserLMS::where('nIDUser',$livechat->patient_id)->first();
|
||||
}
|
||||
$user->notify(new SendNotification($title, $body, $dataNotif));
|
||||
return ApiResponse::apiResponse("Success",['message' => 'Livechat updated successfully'], trans('Message.success'), 200);
|
||||
} else {
|
||||
@@ -188,15 +199,18 @@ class ChatDoctorController extends Controller
|
||||
'doctor_id' => $livechat->doctor_id
|
||||
])->first();
|
||||
$dataNotif = [
|
||||
'channel_id' => $channel->id,
|
||||
'livechat_id' => $livechat->id,
|
||||
'channel_id' => (string)$channel->id,
|
||||
'livechat_id' => (string)$livechat->id,
|
||||
'type' => 'approve-chat'
|
||||
];
|
||||
|
||||
$user = UserLMS::where('nID',$livechat->patient_id)->first();
|
||||
if ($user) {
|
||||
$user->notify(new SendNotification($title, $body, $dataNotif));
|
||||
return ApiResponse::apiResponse("Success",['message' => 'Livechat updated successfully'], trans('Message.success'), 200);
|
||||
if ($user->nIDUser) { // Jika Dependent yang request
|
||||
$user = UserLMS::where('nIDUser',$livechat->patient_id)->first();
|
||||
}
|
||||
$user->notify(new SendNotification($title, $body, $dataNotif));
|
||||
return ApiResponse::apiResponse("Success",['message' => 'Livechat updated successfully'], trans('Message.success'), 200);
|
||||
} else {
|
||||
return Helper::responseJson(
|
||||
status: 'Not Found',
|
||||
@@ -229,14 +243,25 @@ class ChatDoctorController extends Controller
|
||||
'doctor_id' => $livechat->doctor_id
|
||||
])->first();
|
||||
$dataNotif = [
|
||||
'channel_id' => $channel->id,
|
||||
'livechat_id' => $livechat->id,
|
||||
'channel_id' => (string)$channel->id,
|
||||
'livechat_id' => (string)$livechat->id,
|
||||
'type' => 'end-chat'
|
||||
];
|
||||
|
||||
$user = UserLMS::where('nID',$livechat->patient_id)->first();
|
||||
|
||||
// Ambil Send End Chat
|
||||
$message = Message::create([
|
||||
'content' => 'end-chat',
|
||||
'from_user' => $livechat->doctor_id,
|
||||
'channel_id' => $channel->id,
|
||||
'type' => 'end-chat'
|
||||
]);
|
||||
|
||||
if ($user) {
|
||||
if ($user->nIDUser) { // Jika Dependent yang request
|
||||
$user = UserLMS::where('nIDUser',$livechat->patient_id)->first();
|
||||
}
|
||||
$user->notify(new SendNotification($title, $body, $dataNotif));
|
||||
return ApiResponse::apiResponse("Success",['message' => 'Livechat updated successfully'], trans('Message.success'), 200);
|
||||
} else {
|
||||
@@ -271,6 +296,7 @@ class ChatDoctorController extends Controller
|
||||
'organization_id' => $livechat->organization_id,
|
||||
]);
|
||||
|
||||
$prescriptionItem = [];
|
||||
if ($request->prescriptions) {
|
||||
foreach ($request->prescriptions as $prescription) {
|
||||
$prescriptionItem = PrescriptionItem::create([
|
||||
@@ -283,6 +309,44 @@ class ChatDoctorController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
$channel = Channel::where([
|
||||
'member_id' => $livechat->patient_id,
|
||||
'doctor_id' => $livechat->doctor_id
|
||||
])->first();
|
||||
|
||||
|
||||
$data = [
|
||||
'livechat' => $livechat,
|
||||
'prescription_items' => $prescriptionItem
|
||||
];
|
||||
|
||||
// Ambil data dari request
|
||||
$message = Message::create([
|
||||
'content' => json_encode($data),
|
||||
'from_user' => $livechat->doctor_id,
|
||||
'channel_id' => $channel->id,
|
||||
'type' => 'summary'
|
||||
]);
|
||||
|
||||
// Send Pusher
|
||||
ChatMessageSent::dispatch($message);
|
||||
|
||||
$title = 'Decline Livechat';
|
||||
$body = 'Decline Livechat';
|
||||
$dataNotif = [
|
||||
'channel_id' => (string) $channel->id,
|
||||
'livechat_id' => (string) $livechat->id,
|
||||
'type' => 'summary-chat'
|
||||
];
|
||||
$user = UserLMS::where('nID',$livechat->patient_id)->first();
|
||||
if ($user) {
|
||||
if ($user->nIDUser) { // Jika Dependent yang request
|
||||
$user = UserLMS::where('nIDUser',$livechat->patient_id)->first();
|
||||
}
|
||||
$user->notify(new SendNotification($title, $body, $dataNotif));
|
||||
return ApiResponse::apiResponse("Success",['message' => 'Livechat updated successfully'], trans('Message.success'), 200);
|
||||
}
|
||||
|
||||
return ApiResponse::apiResponse("Success",['message' => 'Livechat updated successfully'], trans('Message.success'), 200);
|
||||
} else {
|
||||
return response()->json(['message' => 'Livechat not found'], 404);
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\Models\Organization;
|
||||
use App\Models\Speciality;
|
||||
use App\Models\Livechat;
|
||||
use App\Models\Channel;
|
||||
use App\Models\Message;
|
||||
use App\Models\UserChannel;
|
||||
use App\Models\User as UserAso;
|
||||
use App\Models\OLDLMS\User;
|
||||
@@ -277,7 +278,8 @@ class DuitkuController extends Controller
|
||||
header('Content-Type: application/json');
|
||||
$notif = json_decode($callback);
|
||||
|
||||
// $notif = $request; ini untuk di local
|
||||
// $notif = $request; //ini untuk di local
|
||||
// $callback = $notif; //ini untuk di local
|
||||
|
||||
DB::table('api_logs')
|
||||
->insert([
|
||||
@@ -297,44 +299,10 @@ class DuitkuController extends Controller
|
||||
// Update start chat
|
||||
$livechat->start_date = date('Y-m-d H:i:s');
|
||||
$livechat->save();
|
||||
// Buat dan simpan data channel ke dalam tabel
|
||||
$channel = Channel::updateOrCreate([
|
||||
'name' => $livechat->patient_id .'_' . $request->doctor_id,
|
||||
],
|
||||
[
|
||||
'name' => $livechat->patient_id .'_' . $livechat->doctor_id,
|
||||
'type' => 'Private',
|
||||
'member_id' => $livechat->patient_id,
|
||||
'doctor_id' => $livechat->doctor_id,
|
||||
]);
|
||||
|
||||
// Menggunakan updateOrCreate untuk menambahkan data UserChannel untuk member_id
|
||||
$userChannelMember = UserChannel::updateOrCreate(
|
||||
[
|
||||
'user_id' => $livechat->patient_id,
|
||||
'channel_id' => $channel->id
|
||||
],
|
||||
[
|
||||
'user_id' => $livechat->patient_id,
|
||||
'channel_id' => $channel->id
|
||||
]
|
||||
);
|
||||
|
||||
// Menggunakan updateOrCreate untuk menambahkan data UserChannel untuk doctor_id
|
||||
$userChannelDoctor = UserChannel::updateOrCreate(
|
||||
[
|
||||
'user_id' => $livechat->doctor_id,
|
||||
'channel_id' => $channel->id
|
||||
],
|
||||
[
|
||||
'user_id' => $livechat->doctor_id,
|
||||
'channel_id' => $channel->id
|
||||
]
|
||||
);
|
||||
|
||||
// Send Notification
|
||||
$doctorId = $livechat->doctor_id;
|
||||
$userDokter = UserAso::find($doctorId);
|
||||
$userDokter = UserAso::where('person_id',$doctorId)->first();
|
||||
$title = 'Payment Succes Livechat';
|
||||
$patient = User::where('nID', $livechat->patient_id)->first();
|
||||
$body = 'Payment Succes Livechat from ' . $patient->sFirstName . ' ' . $patient->sLastName;
|
||||
@@ -343,11 +311,22 @@ class DuitkuController extends Controller
|
||||
'doctor_id' => $livechat->doctor_id
|
||||
])->first();
|
||||
$dataNotif = [
|
||||
'channel_id' => $channel->id,
|
||||
'livechat_id' => $livechat->id,
|
||||
'channel_id' => (string) $channel->id,
|
||||
'livechat_id' => (string) $livechat->id,
|
||||
'type' => 'success-payment'
|
||||
];
|
||||
|
||||
$question = $livechat->descriptions;
|
||||
// Ambil data dari request
|
||||
$message = Message::create([
|
||||
'content' => $question,
|
||||
'from_user' => $livechat->patient_id,
|
||||
'channel_id' => $channel->id,
|
||||
'type' => 'first_chat'
|
||||
]);
|
||||
|
||||
$userDokter->notify(new SendNotification($title, $body, $dataNotif));
|
||||
$patient->notify(new SendNotification($title, $body, $dataNotif));
|
||||
|
||||
// Berikan respons yang sesuai ke klien
|
||||
return response()->json(['message' => 'Channel created successfully', 'channel' => $channel]);
|
||||
@@ -362,7 +341,7 @@ class DuitkuController extends Controller
|
||||
|
||||
// Send Notification
|
||||
$doctorId = $livechat->doctor_id;
|
||||
$userDokter = UserAso::find($doctorId);
|
||||
$userDokter = UserAso::where('person_id',$doctorId)->first();
|
||||
$title = 'Payment Failed Livechat';
|
||||
$patient = User::where('nID', $livechat->patient_id)->first();
|
||||
$body = 'Payment Failed Livechat from ' . $patient->sFirstName . ' ' . $patient->sLastName;
|
||||
@@ -371,11 +350,12 @@ class DuitkuController extends Controller
|
||||
'doctor_id' => $livechat->doctor_id
|
||||
])->first();
|
||||
$dataNotif = [
|
||||
'channel_id' => $channel->id,
|
||||
'livechat_id' => $livechat->id,
|
||||
'channel_id' => (string) $channel->id,
|
||||
'livechat_id' => (string) $livechat->id,
|
||||
'type' => 'failed-payment'
|
||||
];
|
||||
$userDokter->notify(new SendNotification($title, $body, $dataNotif));
|
||||
$patient->notify(new SendNotification($title, $body, $dataNotif));
|
||||
return response()->json(['message' => 'User Gagal melakukan pembayaran']);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ use Illuminate\Support\Facades\Http;
|
||||
use Modules\Linksehat\Transformers\Livechat\LivechatResource;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Http\Controllers\DuitkuController;
|
||||
|
||||
use App\Models\UserChannel;
|
||||
use DB;
|
||||
use Illuminate\Contracts\Filesystem\Cloud;
|
||||
use Kreait\Firebase\Messaging\CloudMessage;
|
||||
@@ -156,7 +156,6 @@ class LivechatController extends Controller
|
||||
* Status Livechat
|
||||
* 1=Request, 2=Accept, 3=Decline, 4=Waiting Payment, 5=Success Payment, 6 = End Chat, 7=Payment Failed
|
||||
*/
|
||||
|
||||
$timezone = date_default_timezone_get();
|
||||
$data['request_date'] = date('Y-m-d H:i:s');
|
||||
$data['timezone'] = $timezone;
|
||||
@@ -171,19 +170,55 @@ class LivechatController extends Controller
|
||||
'image_path' => 'https' // Ganti dengan path yang benar jika ada
|
||||
];
|
||||
|
||||
// Buat dan simpan data channel ke dalam tabel
|
||||
$channel = Channel::updateOrCreate([
|
||||
'member_id' => $livechat->patient_id,
|
||||
'doctor_id' => $livechat->doctor_id,
|
||||
],
|
||||
[
|
||||
'name' => $livechat->patient_id .'_' . $livechat->doctor_id,
|
||||
'type' => 'Private',
|
||||
'member_id' => $livechat->patient_id,
|
||||
'doctor_id' => $livechat->doctor_id,
|
||||
]);
|
||||
|
||||
// Menggunakan updateOrCreate untuk menambahkan data UserChannel untuk member_id
|
||||
UserChannel::updateOrCreate(
|
||||
[
|
||||
'user_id' => $livechat->patient_id,
|
||||
'channel_id' => $channel->id
|
||||
],
|
||||
[
|
||||
'user_id' => $livechat->patient_id,
|
||||
'channel_id' => $channel->id
|
||||
]
|
||||
);
|
||||
|
||||
// Menggunakan updateOrCreate untuk menambahkan data UserChannel untuk doctor_id
|
||||
UserChannel::updateOrCreate(
|
||||
[
|
||||
'user_id' => $livechat->doctor_id,
|
||||
'channel_id' => $channel->id
|
||||
],
|
||||
[
|
||||
'user_id' => $livechat->doctor_id,
|
||||
'channel_id' => $channel->id
|
||||
]
|
||||
);
|
||||
|
||||
// Send Notification
|
||||
$doctorId = $livechat->doctor_id;
|
||||
$user = UserAso::find($doctorId);
|
||||
$user = UserAso::where('person_id',$doctorId)->first();
|
||||
$title = 'New Request Livechat';
|
||||
$patient = User::where('nID', $livechat->patient_id)->first();
|
||||
$body = 'Request Livechat from ' . $patient->sFirstName . ' ' . $patient->sLastName;
|
||||
$channel = Channel::where([
|
||||
'member_id' => $livechat->patient_id,
|
||||
'doctor_id' => $livechat->doctor_id
|
||||
])->first();
|
||||
// $channel = Channel::where([
|
||||
// 'member_id' => $livechat->patient_id,
|
||||
// 'doctor_id' => $livechat->doctor_id
|
||||
// ])->first();
|
||||
$dataNotif = [
|
||||
'channel_id' => $channel->id,
|
||||
'livechat_id' => $livechat->id,
|
||||
'channel_id' => (string) $channel->id,
|
||||
'livechat_id' => (string) $livechat->id,
|
||||
'type' => 'request-chat'
|
||||
];
|
||||
|
||||
|
||||
@@ -99,11 +99,11 @@ class HomeResource extends JsonResource
|
||||
};
|
||||
|
||||
if (count($memberProfile) > 0){
|
||||
|
||||
|
||||
$urlAvatarDefault = $this->detail->nIDJenisKelamin == 1 ? 'https://linksehat.dev/assets/img/users/male-avatar.png' : 'https://linksehat.dev/assets/img/users/female-avatar.png';
|
||||
$avatarMember = $this->detail->sImage ?? $urlAvatarDefault;
|
||||
$relationship = DB::connection('oldlms')->table('tm_hubungan_keluarga')->where('nID', $this->nIDHubunganKeluarga)->first('sHubunganKeluarga');
|
||||
|
||||
|
||||
$dataUser = [
|
||||
'id' => $this->nID,
|
||||
'name' => $this->sFirstName . ' ' . $this->sLastName,
|
||||
@@ -117,7 +117,7 @@ class HomeResource extends JsonResource
|
||||
$urlAvatarDefault = $m['detail']['nIDJenisKelamin'] == 1 ? 'https://linksehat.dev/assets/img/users/male-avatar.png' : 'https://linksehat.dev/assets/img/users/female-avatar.png';
|
||||
$avatarMember = $m['detail']['sImage'] ?? $urlAvatarDefault;
|
||||
$relationship = DB::connection('oldlms')->table('tm_hubungan_keluarga')->where('nID', $m['nIDHubunganKeluarga'])->first('sHubunganKeluarga');
|
||||
|
||||
|
||||
$data = [
|
||||
'id' => $m['nID'],
|
||||
'name' => $m['full_name'],
|
||||
@@ -135,17 +135,17 @@ class HomeResource extends JsonResource
|
||||
$memberProfile = User::with('detail')->where('nIDUser', $nID)->get()->toArray();
|
||||
|
||||
$dataMember = User::with('detail')->where('nID', $nID)->get()->first();
|
||||
|
||||
|
||||
if ($this->detail){
|
||||
$urlAvatarDefault = $this->detail->nIDJenisKelamin == 1 ? 'https://linksehat.dev/assets/img/users/male-avatar.png' : 'https://linksehat.dev/assets/img/users/female-avatar.png';
|
||||
} else {
|
||||
$urlAvatarDefault = 'https://linksehat.dev/assets/img/users/male-avatar.png';
|
||||
}
|
||||
$avatar = $this->detail->sImage ?? $urlAvatarDefault;
|
||||
|
||||
|
||||
$avatarMember = $dataMember->detail->sImage ?? $urlAvatarDefault;
|
||||
$relationship = DB::connection('oldlms')->table('tm_hubungan_keluarga')->where('nID', $this->nIDHubunganKeluarga)->first('sHubunganKeluarga');
|
||||
|
||||
|
||||
$dataUser = [
|
||||
'id' => $dataMember->nID,
|
||||
'name' => $dataMember->sFirstName . ' ' . $dataMember->sLastName,
|
||||
@@ -159,14 +159,14 @@ class HomeResource extends JsonResource
|
||||
$urlAvatarDefault = $m['detail']['nIDJenisKelamin'] == 1 ? 'https://linksehat.dev/assets/img/users/male-avatar.png' : 'https://linksehat.dev/assets/img/users/female-avatar.png';
|
||||
$avatarMember = $m['detail']['sImage'] ?? $urlAvatarDefault;
|
||||
$relationship = DB::connection('oldlms')->table('tm_hubungan_keluarga')->where('nID', $m['nIDHubunganKeluarga'])->first('sHubunganKeluarga');
|
||||
|
||||
|
||||
$data = [
|
||||
'id' => $m['nID'],
|
||||
'name' => $m['full_name'],
|
||||
'relationship' => $relationship->sHubunganKeluarga,
|
||||
'avatar' => $avatarMember,
|
||||
];
|
||||
|
||||
|
||||
array_push( $dataMemberProfile, $data);
|
||||
}
|
||||
}
|
||||
@@ -195,6 +195,7 @@ class HomeResource extends JsonResource
|
||||
$specialist = 'Umum';
|
||||
$year = 0;
|
||||
$price = 0;
|
||||
$organizationId = 0;
|
||||
if (!empty($doctor['person']['start_date_work'])) {
|
||||
$starExperience = Carbon::parse($doctor['person']['start_date_work'])->format('Y-m-d');
|
||||
$experience = Carbon::createFromFormat('Y-m-d', $starExperience);
|
||||
@@ -203,15 +204,19 @@ class HomeResource extends JsonResource
|
||||
if ($doctor['practitioner_roles']) {
|
||||
if ($doctor['practitioner_roles'][0]['speciality']){
|
||||
$specialist = $doctor['practitioner_roles'][0]['speciality']['name'];
|
||||
}
|
||||
}
|
||||
if ($doctor['practitioner_roles'][0]['price']){
|
||||
$price = $doctor['practitioner_roles'][0]['price'];
|
||||
}
|
||||
}
|
||||
if ($doctor['practitioner_roles'][0]['organization_id']){
|
||||
$organizationId = $doctor['practitioner_roles'][0]['organization_id'];
|
||||
}
|
||||
}
|
||||
$data = [
|
||||
'id' => $doctor['id'],
|
||||
'id' => $doctor['person']['id'],
|
||||
'full_name' => $doctor['person']['name'],
|
||||
'specialist' => $specialist,
|
||||
'organization_id' => $organizationId,
|
||||
'experience' => $year,
|
||||
'review' => $doctor['person']['review'],
|
||||
'price' => $price,
|
||||
@@ -224,8 +229,8 @@ class HomeResource extends JsonResource
|
||||
$hospitalList = [];
|
||||
|
||||
$hospitals = Organization::where([
|
||||
'type' => 'hospital',
|
||||
'status' => 'active',
|
||||
'type' => 'hospital',
|
||||
'status' => 'active',
|
||||
])
|
||||
->with('currentAddress')
|
||||
->get()->toArray();
|
||||
@@ -248,7 +253,7 @@ class HomeResource extends JsonResource
|
||||
if ($lat && $lang && $request->longitude && $request->latitude){
|
||||
$radius = round(Helper::calculateDistance($lat, $lang, $request->latitude, $request->longitude), 2);
|
||||
}
|
||||
|
||||
|
||||
$data = [
|
||||
'name' => $hospital['name'],
|
||||
'radius' => $radius,
|
||||
@@ -259,7 +264,7 @@ class HomeResource extends JsonResource
|
||||
array_push($hospitalList, $data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
usort($hospitalList, function($a, $b) {
|
||||
return $a['radius'] <=> $b['radius'];
|
||||
});
|
||||
|
||||
@@ -48,6 +48,7 @@ class LivechatResource extends JsonResource
|
||||
$specialist = 'Umum';
|
||||
$year = 0;
|
||||
$price = 0;
|
||||
$organizationId = 0;
|
||||
if (!empty($doctor['person']['start_date_work'])) {
|
||||
$starExperience = Carbon::parse($doctor['person']['start_date_work'])->format('Y-m-d');
|
||||
$experience = Carbon::createFromFormat('Y-m-d', $starExperience);
|
||||
@@ -56,15 +57,19 @@ class LivechatResource extends JsonResource
|
||||
if ($doctor['practitioner_roles']) {
|
||||
if ($doctor['practitioner_roles'][0]['speciality']){
|
||||
$specialist = $doctor['practitioner_roles'][0]['speciality']['name'];
|
||||
}
|
||||
}
|
||||
if ($doctor['practitioner_roles'][0]['price']){
|
||||
$price = $doctor['practitioner_roles'][0]['price'];
|
||||
}
|
||||
}
|
||||
if ($doctor['practitioner_roles'][0]['organization_id']){
|
||||
$organizationId = $doctor['practitioner_roles'][0]['organization_id'];
|
||||
}
|
||||
}
|
||||
$data = [
|
||||
'id' => $doctor['id'],
|
||||
'id' => $doctor['person']['id'],
|
||||
'full_name' => $doctor['person']['name'],
|
||||
'specialist' => $specialist,
|
||||
'organization_id' => $organizationId,
|
||||
'experience' => $year,
|
||||
'review' => $doctor['person']['review'],
|
||||
'price' => $price,
|
||||
@@ -76,7 +81,7 @@ class LivechatResource extends JsonResource
|
||||
return [
|
||||
'jadwal_weekday' => 'Senin - Jumat (08:00 - 17:30)',
|
||||
'jadwal_weekend' => 'Sabtu (08:00 - 12:00)',
|
||||
'doctors_livechat' =>
|
||||
'doctors_livechat' =>
|
||||
$doctorsLivechat
|
||||
,
|
||||
'specialist' => $specialists
|
||||
|
||||
@@ -67,5 +67,11 @@ class Kernel extends HttpKernel
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
'linksehat.old.auth' => \App\Http\Middleware\LinksehatOldAuthMiddleware::class,
|
||||
|
||||
// Role
|
||||
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
|
||||
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
|
||||
'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ class Drug extends Model
|
||||
'remark',
|
||||
'selling_unit_id',
|
||||
'status',
|
||||
'price',
|
||||
'active',
|
||||
];
|
||||
|
||||
|
||||
19
app/Models/Navigations.php
Normal file
19
app/Models/Navigations.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Navigations extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'path',
|
||||
'icon',
|
||||
'name',
|
||||
'parent_id',
|
||||
'permission'
|
||||
];
|
||||
}
|
||||
@@ -14,6 +14,7 @@ class NotificationToken extends Model
|
||||
'type',
|
||||
'token',
|
||||
'status',
|
||||
'device_id'
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
|
||||
@@ -19,6 +19,7 @@ class Prescription extends Model
|
||||
'sSource',
|
||||
'nIDUser',
|
||||
'sRegID',
|
||||
'sStatus',
|
||||
'sKodeResep',
|
||||
'sDiagnose',
|
||||
'sKodeRS',
|
||||
|
||||
@@ -19,6 +19,7 @@ class PrescriptionItem extends Model
|
||||
'sSatuan',
|
||||
'sSigna',
|
||||
'sNote',
|
||||
'nHarga',
|
||||
'isRacikan',
|
||||
'ParentCode',
|
||||
];
|
||||
|
||||
@@ -15,4 +15,9 @@ class Prescription extends Model
|
||||
'organization_id',
|
||||
'icd_code'
|
||||
];
|
||||
|
||||
public function items()
|
||||
{
|
||||
return $this->hasMany(PrescriptionItem::class, 'prescription_id');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,4 +17,8 @@ class PrescriptionItem extends Model
|
||||
'signa',
|
||||
'direction'
|
||||
];
|
||||
|
||||
public function drug(){
|
||||
return $this->hasOne(Drug::class, 'id');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
@@ -29,6 +33,7 @@ class User extends Authenticatable
|
||||
'phone',
|
||||
'otp',
|
||||
'otp_created_at',
|
||||
'role_id'
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -53,13 +58,15 @@ class User extends Authenticatable
|
||||
|
||||
public $with = [
|
||||
'metas',
|
||||
'person'
|
||||
'person',
|
||||
'role',
|
||||
];
|
||||
|
||||
public $appends = [
|
||||
'meta',
|
||||
'avatar_url',
|
||||
'full_name'
|
||||
'full_name',
|
||||
'permissions'
|
||||
];
|
||||
|
||||
public function getAvatarUrlAttribute()
|
||||
@@ -82,6 +89,24 @@ class User extends Authenticatable
|
||||
return (object) $orgMeta;
|
||||
}
|
||||
|
||||
public function getPermissionsAttribute()
|
||||
{
|
||||
$roleId = $this->role_id;
|
||||
|
||||
if (!$roleId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Ambil permissions dari role_has_permissions dan permissions tabel
|
||||
$permissions = DB::table('role_has_permissions')
|
||||
->join('permissions', 'role_has_permissions.permission_id', '=', 'permissions.id')
|
||||
->where('role_has_permissions.role_id', $roleId)
|
||||
->select('permissions.id', 'permissions.name', 'permissions.guard_name')
|
||||
->get();
|
||||
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
public function managedCorporates()
|
||||
{
|
||||
return $this->belongsToMany(Corporate::class, 'corporate_manager', 'user_id', 'corporate_id');
|
||||
@@ -97,7 +122,12 @@ class User extends Authenticatable
|
||||
return $this->belongsTo(Person::class, 'person_id');
|
||||
}
|
||||
|
||||
public function ownedPersons()
|
||||
public function role()
|
||||
{
|
||||
return $this->belongsTo(Role::class, 'role_id');
|
||||
}
|
||||
|
||||
public function ownedPersons()
|
||||
{
|
||||
return $this->hasMany(Person::class, 'owner_user_id');
|
||||
}
|
||||
@@ -114,6 +144,6 @@ class User extends Authenticatable
|
||||
|
||||
public function routeNotificationForFcm()
|
||||
{
|
||||
return $this->notificationTokens()->pluck('token')->toArray();
|
||||
return $this->notificationTokens()->orderBy('created_at', 'desc')->pluck('token')->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,22 +54,27 @@ class SendNotification extends Notification
|
||||
'body' => $this->body,
|
||||
];
|
||||
|
||||
if (count($deviceTokens)){
|
||||
foreach($deviceTokens as $token) {
|
||||
$message = CloudMessage::withTarget('token', $token)
|
||||
->withNotification($notification) // optional
|
||||
->withData($this->data);
|
||||
Firebase::messaging()->send($message);
|
||||
}
|
||||
}
|
||||
// if (count($deviceTokens)){
|
||||
// foreach($deviceTokens as $token) {
|
||||
// $message = CloudMessage::withTarget('token', $token)
|
||||
// ->withNotification($notification) // optional
|
||||
// ->withData($this->data);
|
||||
// Firebase::messaging()->send($message);
|
||||
// }
|
||||
// }
|
||||
|
||||
// $datas = [
|
||||
// 'channel_id' => 2,
|
||||
|
||||
// ]
|
||||
|
||||
$dataFcm = FcmMessage::create()
|
||||
->setToken($deviceTokens[0])
|
||||
->setData([])
|
||||
->setData($this->data)
|
||||
->setNotification(
|
||||
FcmNotification::create()
|
||||
->setTitle('ini title')
|
||||
->setBody('ini body')
|
||||
->setTitle($this->title)
|
||||
->setBody($this->body)
|
||||
)
|
||||
->setAndroid(
|
||||
AndroidConfig::create()
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('notification_tokens', function (Blueprint $table) {
|
||||
$table->string('device_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('notification_tokens', function (Blueprint $table) {
|
||||
$table->dropColumn('device_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
<?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('navigations', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('title');
|
||||
$table->string('path')->nullable();
|
||||
$table->string('icon');
|
||||
$table->string('permission');
|
||||
$table->foreignId('parent_id');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('navigations');
|
||||
}
|
||||
};
|
||||
247
database/seeders/NavigationSeeder.php
Normal file
247
database/seeders/NavigationSeeder.php
Normal file
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Models\Navigations;
|
||||
|
||||
class NavigationSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$menuItems = [
|
||||
// DOCTORS & HOSPITALS
|
||||
[
|
||||
'title' => 'Dashboard',
|
||||
'path' => '/dashboard',
|
||||
'permission' => 'dashboard'
|
||||
],
|
||||
// DOCTORS & HOSPITALS
|
||||
[
|
||||
'title' => 'DOCTORS & HOSPITALS',
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Doctors',
|
||||
'path' => '/master/doctors',
|
||||
'permission' => 'doctor-list'
|
||||
],
|
||||
[
|
||||
'title' => 'Hospitals',
|
||||
'path' => '/master/hospitals',
|
||||
'permission' => 'hospital-list'
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// PHARMACY & DELIVERY MANAGEMENT
|
||||
[
|
||||
'title' => 'PHARMACY & DELIVERY MANAGEMENT',
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Drug',
|
||||
'path' => '/master/drugs',
|
||||
'permission' => 'drug-list'
|
||||
],
|
||||
[
|
||||
'title' => 'Inventory',
|
||||
'path' => '/inventory',
|
||||
'permission' => null
|
||||
],
|
||||
[
|
||||
'title' => 'Delivery Services',
|
||||
'path' => '/delivery',
|
||||
'permission' => null
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// STATION BENEFIT & MEMBERSHIP
|
||||
[
|
||||
'title' => 'STATION BENEFIT & MEMBERSHIP',
|
||||
'openWhen' => ['/corporates', '/formularium', '/diagnosis', '/hospitals'],
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Corporate',
|
||||
'path' => '/corporates',
|
||||
'permission' => 'corporate-list',
|
||||
],
|
||||
// ['title' => 'Corporate Create', 'path' => '/corporates/create'],
|
||||
[
|
||||
'title' => 'Formularium',
|
||||
'path' => '/master/formularium-template-v2',
|
||||
'permission' => 'formularium-list',
|
||||
],
|
||||
[
|
||||
'title' => 'Master ICD-10 Diagnosis',
|
||||
'path' => '/master/diagnosis',
|
||||
'permission' => 'diagnosis-list',
|
||||
],
|
||||
[
|
||||
'title' => 'Hospitals',
|
||||
'path' => '/hospitals',
|
||||
'permission' => null,
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// CLAIM REQUEST
|
||||
[
|
||||
'title' => 'CLAIM REQUEST',
|
||||
'path' => '/claim-requests',
|
||||
'permission' => 'claim-request-list'
|
||||
],
|
||||
// CLAIM MANAGEMENT
|
||||
[
|
||||
'title' => 'CLAIM MANAGEMENT',
|
||||
'path' => '/claims',
|
||||
'permission' => 'claim-management-list'
|
||||
],
|
||||
// CASE MANAGEMENT
|
||||
[
|
||||
'title' => 'CASE MANAGEMENT',
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Daily Monitoring',
|
||||
'path' => '/case_management/daily_monitoring',
|
||||
'permission' => 'daily-monitoring-list'
|
||||
],
|
||||
// ['title' => 'Laboratorium Result', 'path' => '/case_management/laboratorium_result'],
|
||||
[
|
||||
'title' => 'Inpatient Monitoring',
|
||||
'path' => '/case_management/inpatient_monitoring',
|
||||
'permission' => 'final-log-list'
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// CUSTOMER SERVICES
|
||||
[
|
||||
'title' => 'CUSTOMER SERVICES',
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Request',
|
||||
'path' => '/custormer-service/request',
|
||||
'permission' => 'request-log-list'
|
||||
],
|
||||
// ['title' => 'Membership', 'path' => '/cs-membership'],
|
||||
[
|
||||
'title' => 'Final LOG',
|
||||
'path' => '/custormer-service/final-log',
|
||||
'permission' => 'final-log-list'
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// REPORT
|
||||
[
|
||||
'title' => 'REPORT',
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Files Provider',
|
||||
'path' => 'report/files-provider',
|
||||
'permission' => 'report-files-provider-list'
|
||||
],
|
||||
[
|
||||
'title' => 'Letter of Guarantee',
|
||||
'path' => '/report/logs',
|
||||
'permission' => 'report-log-list'
|
||||
],
|
||||
[
|
||||
'title' => 'Appointment',
|
||||
'path' => '/report/appointments',
|
||||
'permission' => 'report-appointment-list'
|
||||
],
|
||||
[
|
||||
'title' => 'Live Chat',
|
||||
'path' => '/report/live-chat',
|
||||
'permission' => 'report-livechat-list'
|
||||
],
|
||||
[
|
||||
'title' => 'Linksehat Payment',
|
||||
'path' => '/report/linksehat-payments',
|
||||
'permission' => 'report-livechat-payment'
|
||||
],
|
||||
// ['title' => 'Prescription', 'path' => '/report/prescription'],
|
||||
[
|
||||
'title' => 'Doctor Rating',
|
||||
'path' => '/report/doctorrating',
|
||||
'permission' => 'report-doctor-rating'
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// MASTER
|
||||
[
|
||||
'title' => 'MASTER',
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Diagnosis',
|
||||
'path' => '/master/diagnosis',
|
||||
'permission' => 'diagnosis-list'
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// USER MANAGEMENT
|
||||
[
|
||||
'title' => 'USER MANAGEMENT',
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'User Role',
|
||||
'path' => '/user-role',
|
||||
'permission' => 'user-role-list'
|
||||
],
|
||||
[
|
||||
'title' => 'User Access',
|
||||
'path' => '/user-access',
|
||||
'permission' => 'user-access-list'
|
||||
],
|
||||
],
|
||||
'permission' => null
|
||||
],
|
||||
// LINKING TOOLS
|
||||
[
|
||||
'title' => 'LINKING TOOLS',
|
||||
'path' => '/linking',
|
||||
'permission' => 'linkking-list'
|
||||
],
|
||||
// E-PRESCRIPTION
|
||||
[
|
||||
'title' => 'E-PRESCRIPTION',
|
||||
'path' => '/e-prescription/live-chat',
|
||||
'permission' => 'prescription-list'
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($menuItems as $menuItemData) {
|
||||
$menuItem = Navigations::updateOrCreate([
|
||||
'title' => $menuItemData['title']
|
||||
],
|
||||
[
|
||||
'title' => $menuItemData['title'],
|
||||
'path' => $menuItemData['path'] ?? null,
|
||||
'permission' => $menuItemData['permission']
|
||||
]);
|
||||
|
||||
if (isset($menuItemData['children'])) {
|
||||
foreach ($menuItemData['children'] as $childData) {
|
||||
$menuItemChildren = Navigations::updateOrCreate([
|
||||
'title' => $childData['title']
|
||||
],
|
||||
[
|
||||
'title' => $childData['title'],
|
||||
'path' => $childData['path'] ?? null,
|
||||
'parent_id' => $menuItem->id,
|
||||
'permission' => $childData['permission']
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
81
database/seeders/PermissionTableSeeder.php
Normal file
81
database/seeders/PermissionTableSeeder.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
|
||||
|
||||
class PermissionTableSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$permissions = [
|
||||
'dashboard',
|
||||
'doctor-list',
|
||||
'doctor-create',
|
||||
'doctor-edit',
|
||||
'doctor-delete',
|
||||
'hospital-list',
|
||||
'hospital-create',
|
||||
'hospital-edit',
|
||||
'hospital-delete',
|
||||
'drug-list',
|
||||
'drug-create',
|
||||
'drug-edit',
|
||||
'drug-delete',
|
||||
'corporate-list',
|
||||
'corporate-create',
|
||||
'corporate-edit',
|
||||
'corporate-delete',
|
||||
'formularium-list',
|
||||
'formularium-create',
|
||||
'formularium-edit',
|
||||
'formularium-delete',
|
||||
'diagnosis-list',
|
||||
'diagnosis-create',
|
||||
'diagnosis-edit',
|
||||
'diagnosis-delete',
|
||||
'claim-request-list',
|
||||
'claim-request-create',
|
||||
'claim-request-edit',
|
||||
'claim-request-delete',
|
||||
'claim-management-list',
|
||||
'claim-management-create',
|
||||
'claim-management-edit',
|
||||
'claim-management-delete',
|
||||
'daily-monitoring-list',
|
||||
'request-log-list',
|
||||
'request-log-create',
|
||||
'request-log-edit',
|
||||
'request-log-delete',
|
||||
'final-log-list',
|
||||
'final-log-create',
|
||||
'final-log-edit',
|
||||
'final-log-delete',
|
||||
'report-files-provider-list',
|
||||
'report-letter-of-guarante-list',
|
||||
'report-log-list',
|
||||
'report-appointment-list',
|
||||
'report-livechat-list',
|
||||
'report-livechat-payment',
|
||||
'report-doctor-rating',
|
||||
'user-role-list',
|
||||
'user-access-list'
|
||||
];
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
Permission::updateOrCreate(['name' => $permission],
|
||||
[
|
||||
'name' => $permission,
|
||||
'guard_name' => 'web'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,3 +126,29 @@ export type UserPost = {
|
||||
message: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type Role = {
|
||||
id: number;
|
||||
name: string;
|
||||
guard_name: string;
|
||||
permissions: number[]
|
||||
};
|
||||
|
||||
export type Permisions = {
|
||||
name: string;
|
||||
guard_name: string;
|
||||
id: number
|
||||
}[]
|
||||
|
||||
export type UserAccess = {
|
||||
id: number;
|
||||
username: string;
|
||||
email: string;
|
||||
person: Person;
|
||||
role: Role;
|
||||
}
|
||||
|
||||
export type Person = {
|
||||
name: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
// components
|
||||
import SvgIconStyle from '../../../components/SvgIconStyle';
|
||||
import axios from '@/utils/axios';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@@ -19,8 +22,6 @@ export const accessGroup = {
|
||||
admin: ["/report/logs"]
|
||||
}
|
||||
|
||||
|
||||
|
||||
const navConfig = [
|
||||
// GENERAL
|
||||
// ----------------------------------------------------------------------
|
||||
@@ -117,8 +118,8 @@ const navConfig = [
|
||||
{
|
||||
title: 'USER MANAGEMENT',
|
||||
children: [
|
||||
{ title: 'User Access', path: '/master/diagnosis' },
|
||||
{ title: 'User Role', path: '/master/diagnosis' },
|
||||
{ title: 'User Role', path: '/user-role' },
|
||||
{ title: 'User Access', path: '/user-access' },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
// @mui
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
@@ -15,11 +15,12 @@ import Logo from '../../../components/Logo';
|
||||
import Scrollbar from '../../../components/Scrollbar';
|
||||
import { NavSectionVertical } from '../../../components/nav-section';
|
||||
//
|
||||
import navConfig from './NavConfig';
|
||||
// import navConfig from './NavConfig';
|
||||
import NavbarDocs from './NavbarDocs';
|
||||
import NavbarAccount from './NavbarAccount';
|
||||
import CollapseButton from './CollapseButton';
|
||||
import useAuth from '@/hooks/useAuth';
|
||||
import axios from '@/utils/axios';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@@ -48,7 +49,49 @@ export default function NavbarVertical({ isOpenSidebar, onCloseSidebar }: Props)
|
||||
const isDesktop = useResponsive('up', 'lg');
|
||||
|
||||
const { isCollapse, collapseClick, collapseHover, onToggleCollapse, onHoverEnter, onHoverLeave } =
|
||||
useCollapseDrawer();
|
||||
useCollapseDrawer();
|
||||
|
||||
const [navConfig, setNavConfig] = useState([]);
|
||||
useEffect(() => {
|
||||
const fetchNavConfig = async () => {
|
||||
try {
|
||||
const response = await axios.get('/navigations');
|
||||
const data = response.data.items;
|
||||
// Ambil data izin pengguna dari user state atau API
|
||||
const userPermissions = user.permissions.map(permission => permission.name);
|
||||
|
||||
// Fungsi untuk memeriksa apakah pengguna memiliki izin untuk item tertentu
|
||||
const hasPermission = (permission) => {
|
||||
return userPermissions.includes(permission);
|
||||
};
|
||||
// Filter data berdasarkan izin pengguna
|
||||
const filteredNavConfig = data.map(section => {
|
||||
if (section.children && section.children.length > 0) {
|
||||
// Cek apakah ada satu atau lebih children yang memiliki izin
|
||||
const filteredChildren = section.children.filter(child => hasPermission(child.permission));
|
||||
|
||||
if (filteredChildren.length > 0) {
|
||||
return {
|
||||
...section,
|
||||
children: filteredChildren
|
||||
};
|
||||
} else {
|
||||
return null; // Skip sections where no children have permissions
|
||||
}
|
||||
}
|
||||
// Jika tidak ada children, cek izin untuk section itu sendiri
|
||||
return hasPermission(section.permission) ? section : null;
|
||||
}).filter(section => section !== null);
|
||||
|
||||
setNavConfig([{ items: filteredNavConfig }]);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch nav config:', error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchNavConfig();
|
||||
}, [user]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpenSidebar) {
|
||||
@@ -57,15 +100,15 @@ export default function NavbarVertical({ isOpenSidebar, onCloseSidebar }: Props)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [pathname]);
|
||||
|
||||
const filteredItems = navConfig.filter(section => {
|
||||
return section.items.some(item => {
|
||||
return item.title === 'E-PRESCRIPTION';
|
||||
});
|
||||
});
|
||||
// const filteredItems = navConfig.filter(section => {
|
||||
// return section.items.some(item => {
|
||||
// return item.title === 'E-PRESCRIPTION';
|
||||
// });
|
||||
// });
|
||||
|
||||
const filteredData = filteredItems.map(section => ({
|
||||
items: section.items.filter(item => item.title === "E-PRESCRIPTION")
|
||||
}));
|
||||
// const filteredData = filteredItems.map(section => ({
|
||||
// items: section.items.filter(item => item.title === "E-PRESCRIPTION")
|
||||
// }));
|
||||
|
||||
const renderContent = (
|
||||
<Scrollbar
|
||||
@@ -101,7 +144,7 @@ export default function NavbarVertical({ isOpenSidebar, onCloseSidebar }: Props)
|
||||
<NavbarAccount isCollapse={isCollapse} />
|
||||
</Stack>
|
||||
|
||||
<NavSectionVertical navConfig={user.role_id == 5 ? filteredData : navConfig} isCollapse={isCollapse} />
|
||||
<NavSectionVertical navConfig={navConfig} isCollapse={isCollapse} />
|
||||
|
||||
<Box sx={{ flexGrow: 1 }} />
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import {useContext, useEffect, useMemo, useState } from 'react';
|
||||
import axios from '../../../utils/axios';
|
||||
import UserAccessForm from './Form';
|
||||
import { Role, UserAccess } from '../../../@types/user';
|
||||
|
||||
|
||||
|
||||
export default function UserAccessCreate() {
|
||||
const { id } = useParams();
|
||||
const [ currentUserAccess, setCurrentUserAccess ] = useState<UserAccess>();
|
||||
const [ roles, setRole ] = useState<any>();
|
||||
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const isEdit = !!id;
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit) {
|
||||
axios.get('/user/access/'+id)
|
||||
.then((res) => {
|
||||
setCurrentUserAccess(res.data);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.response.status === 404) {
|
||||
navigate('/404');
|
||||
}
|
||||
})
|
||||
}
|
||||
axios.get('/role-list')
|
||||
.then((res)=> {
|
||||
setRole(res.data)
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.response.status === 404) {
|
||||
navigate('/404');
|
||||
}
|
||||
})
|
||||
|
||||
}, [id]);
|
||||
|
||||
|
||||
return (
|
||||
<Page title= "User Access">
|
||||
<HeaderBreadcrumbs
|
||||
sx={{ px: 2 }}
|
||||
heading={'User Access'}
|
||||
links={[
|
||||
{
|
||||
name: 'User Access',
|
||||
href: '/user-access',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<UserAccessForm isEdit={isEdit} currentUserAccess={currentUserAccess} roles={roles}/>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
147
frontend/dashboard/src/pages/UserManagement/UserAccess/Form.tsx
Normal file
147
frontend/dashboard/src/pages/UserManagement/UserAccess/Form.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
import * as Yup from 'yup';
|
||||
import { LoadingButton } from "@mui/lab";
|
||||
import { Box, Card, Grid, Stack, Typography } from "@mui/material";
|
||||
import { Role, UserAccess } from "../../../@types/user";
|
||||
import { FormProvider, RHFSelect, RHFSwitch, RHFTextField } from "../../../components/hook-form";
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import axios from '../../../utils/axios';
|
||||
import palette from '@/theme/palette';
|
||||
|
||||
type Props = {
|
||||
isEdit: boolean;
|
||||
currentUserAccess?: UserAccess;
|
||||
roles: Role
|
||||
};
|
||||
|
||||
export default function AccsessForm({ isEdit, currentUserAccess, roles }: Props) {
|
||||
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams();
|
||||
|
||||
const NewCorporatePlanSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
});
|
||||
|
||||
console.log(currentUserAccess, 'test')
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
name: currentUserAccess?.person?.name || '',
|
||||
username: currentUserAccess?.username || '',
|
||||
email: currentUserAccess?.email || '',
|
||||
roles: currentUserAccess?.role?.id || [],
|
||||
password: '',
|
||||
}),
|
||||
[currentUserAccess]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit && currentUserAccess) {
|
||||
reset(defaultValues);
|
||||
}
|
||||
if (!isEdit) {
|
||||
reset(defaultValues);
|
||||
}
|
||||
}, [isEdit, currentUserAccess]);
|
||||
|
||||
const methods = useForm({
|
||||
resolver: yupResolver(NewCorporatePlanSchema),
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
const {
|
||||
reset,
|
||||
watch,
|
||||
control,
|
||||
setValue,
|
||||
getValues,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
|
||||
const onSubmit = async (data: any) => {
|
||||
|
||||
console.log(data);
|
||||
if (!isEdit) {
|
||||
await axios
|
||||
.post('/user/access', data)
|
||||
.then((res) => {
|
||||
enqueueSnackbar('User created successfully', { variant: 'success' });
|
||||
})
|
||||
.then((res) => {
|
||||
navigate('/user-access', { replace: true });
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
if (response.status === 422) {
|
||||
for (const [key, value] of Object.entries(response.data.errors)) {
|
||||
setError(key, { message: value[0] });
|
||||
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
|
||||
}
|
||||
}
|
||||
else {
|
||||
enqueueSnackbar('Create Failed : '+ response.data.message, { variant: 'error' });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await axios
|
||||
.put('/user/access/' + currentUserAccess?.id, data)
|
||||
.then((res) => {
|
||||
enqueueSnackbar('User updated successfully', { variant: 'success' });
|
||||
})
|
||||
.then((res) => {
|
||||
navigate('/user-access' , { replace: true });
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const optionsRoles = roles?.data?.map(item => ({
|
||||
value: item.id,
|
||||
label: item.name
|
||||
})) ?? [];
|
||||
|
||||
if (optionsRoles.length > 0) {
|
||||
optionsRoles.unshift({ value: '', label: '' });
|
||||
}
|
||||
|
||||
return (
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Box sx={{ px: 2 }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} sm={12}>
|
||||
<Card sx={{ px: 3, py: 4 }}>
|
||||
<Stack spacing={2}>
|
||||
<Typography variant="h6" color={palette.light.primary.main}>User Access</Typography>
|
||||
<RHFTextField name="name" label="Name" />
|
||||
<RHFTextField name="username" label="Username" />
|
||||
<RHFTextField type="email" name="email" label="Email" />
|
||||
<RHFTextField type="password" name="password" label="Password" />
|
||||
<RHFSelect name="roles" label="Roles">
|
||||
{optionsRoles.map((option, index) => (
|
||||
<option key={index} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</RHFSelect>
|
||||
|
||||
|
||||
<LoadingButton type="submit" variant="contained" size="large" fullWidth={true} loading={isSubmitting}>
|
||||
{ isEdit? 'Update' : 'Create' }
|
||||
</LoadingButton>
|
||||
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</FormProvider>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
// @mui
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
Collapse,
|
||||
Container,
|
||||
FormControl,
|
||||
Grid,
|
||||
IconButton,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
OutlinedInput,
|
||||
Paper,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
Badge,
|
||||
Stack,
|
||||
} from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import ArrowForwardIosSharpIcon from '@mui/icons-material/ArrowForwardIosSharp';
|
||||
import MuiAccordion, { AccordionProps } from '@mui/material/Accordion';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import MuiAccordionSummary, {
|
||||
AccordionSummaryProps,
|
||||
} from '@mui/material/AccordionSummary';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import axios from '../../../utils/axios';
|
||||
import { ConfiguredCorporateContext } from '@/contexts/ConfiguredCorporateContext';
|
||||
import MuiAccordionDetails from '@mui/material/AccordionDetails';
|
||||
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
|
||||
import { Corporate } from '@/@types/corporates';
|
||||
import { fDate, fDateTime } from '@/utils/formatTime';
|
||||
|
||||
const Accordion = styled((props: AccordionProps) => (
|
||||
<MuiAccordion disableGutters elevation={0} square {...props} />
|
||||
))(({ theme }) => ({
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
'&:not(:last-child)': {
|
||||
borderBottom: 0,
|
||||
},
|
||||
'&:before': {
|
||||
display: 'none',
|
||||
},
|
||||
}));
|
||||
|
||||
const AccordionSummary = styled((props: AccordionSummaryProps) => (
|
||||
<MuiAccordionSummary
|
||||
expandIcon={<ArrowForwardIosSharpIcon sx={{ fontSize: '0.9rem' }} />}
|
||||
{...props}
|
||||
/>
|
||||
))(({ theme }) => ({
|
||||
backgroundColor:
|
||||
theme.palette.mode === 'dark'
|
||||
? 'rgba(255, 255, 255, .05)'
|
||||
: 'rgba(0, 0, 0, .03)',
|
||||
flexDirection: 'row-reverse',
|
||||
'& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': {
|
||||
transform: 'rotate(90deg)',
|
||||
},
|
||||
'& .MuiAccordionSummary-content': {
|
||||
marginLeft: theme.spacing(1),
|
||||
},
|
||||
}));
|
||||
|
||||
const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({
|
||||
padding: theme.spacing(2),
|
||||
borderTop: '1px solid rgba(0, 0, 0, .125)',
|
||||
}));
|
||||
|
||||
export default function CustomizedAccordions() {
|
||||
const [expanded, setExpanded] = React.useState<string | false>('panel1');
|
||||
|
||||
const handleChange =
|
||||
(panel: string) => (event: React.SyntheticEvent, newExpanded: boolean) => {
|
||||
setExpanded(newExpanded ? panel : false);
|
||||
};
|
||||
const pageTitle = 'Diagnosis Template History';
|
||||
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { id } = useParams();
|
||||
|
||||
const [corporate, setCorporate] = useState<Corporate | null>();
|
||||
const [ currentCorporate, setCurrentCorporate ] = useState<Corporate>();
|
||||
|
||||
const configuredCorporateContext = useContext(ConfiguredCorporateContext);
|
||||
|
||||
useEffect(() => {
|
||||
setCorporate(configuredCorporateContext.currentCorporate);
|
||||
const model = 'App\\Models\\IcdTemplate';
|
||||
const url = `/audittrail/${id}?model=${model}`;
|
||||
axios.get(url)
|
||||
.then((res) => {
|
||||
setCurrentCorporate(res.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Terjadi kesalahan:', error);
|
||||
});
|
||||
|
||||
}, [configuredCorporateContext]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<HeaderBreadcrumbs
|
||||
heading={pageTitle}
|
||||
links={[
|
||||
{
|
||||
name: 'Master',
|
||||
href: '/master/diagnosis-template',
|
||||
},
|
||||
{
|
||||
name: 'Diagnosis Template',
|
||||
href: '/master/diagnosis-template',
|
||||
},
|
||||
// {
|
||||
// name: 'Audittrail ICD',
|
||||
// href: '/corporate/' + id + '/plans',
|
||||
// },
|
||||
]}
|
||||
/>
|
||||
{currentCorporate?.data.map((item, index) => (
|
||||
<Accordion
|
||||
key={index}
|
||||
expanded={expanded === `panel${index}`}
|
||||
onChange={handleChange(`panel${index}`)}
|
||||
>
|
||||
<AccordionSummary
|
||||
aria-controls={`panel${index}d-content`}
|
||||
id={`panel${index}d-header`}
|
||||
>
|
||||
<Typography>{`Data has ${item.action} by ${item.user_id} on ${fDateTime(item.updated_at)}`}</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="center">Field</TableCell>
|
||||
<TableCell align="center">Old Value</TableCell>
|
||||
<TableCell align="center">New Values</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{Object.entries(item.old_values).map(([key, value]) => {
|
||||
let renderedValue;
|
||||
if (key === 'deleted_by' ||
|
||||
key === 'deleted_at' ||
|
||||
key === 'created_by' ||
|
||||
key === 'created_at' ||
|
||||
key === 'updated_by' ||
|
||||
key === 'description'
|
||||
) {
|
||||
return null; // Melewati iterasi saat key adalah 'deleted_by'
|
||||
}
|
||||
switch (key) {
|
||||
case 'welcome_message':
|
||||
renderedValue = item.new_values[key].replace(/<[^>]*>/g, '');
|
||||
value = value.replace(/<[^>]*>/g, '');
|
||||
break;
|
||||
case 'help_text':
|
||||
renderedValue = item.new_values[key].replace(/<[^>]*>/g, '');
|
||||
value = value.replace(/<[^>]*>/g, '');
|
||||
break;
|
||||
case 'active':
|
||||
renderedValue = item.new_values[key] == 1 ? 'Active' : 'Inactive';
|
||||
value = value == 1 ? 'Active' : 'Inactive';
|
||||
break;
|
||||
case 'created_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
case 'updated_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
case 'updated_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
case 'delete_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
default:
|
||||
renderedValue = item.new_values[key];
|
||||
break;
|
||||
}
|
||||
|
||||
const field = key.charAt(0).toUpperCase() + key.slice(1);
|
||||
if (value == renderedValue) {
|
||||
return null
|
||||
} else {
|
||||
return (
|
||||
<TableRow key={key} sx={{ '&:last-child td, &:last-child th': { border: 0 } }}>
|
||||
<TableCell>{`${field}`}</TableCell>
|
||||
<TableCell align="center">{`${value}`}</TableCell>
|
||||
<TableCell align="center">{renderedValue}</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
})}
|
||||
|
||||
</TableBody>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Card, Grid } from "@mui/material";
|
||||
import { useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import useSettings from "../../../hooks/useSettings";
|
||||
import List from "./List";
|
||||
|
||||
|
||||
|
||||
export default function Divisions() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const pageTitle = 'User Access';
|
||||
return (
|
||||
<Page title={ pageTitle }>
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
sx={{ px: 2 }}
|
||||
heading={ pageTitle }
|
||||
links={[
|
||||
{
|
||||
name: 'User Access',
|
||||
href: '/user-access',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<List />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
443
frontend/dashboard/src/pages/UserManagement/UserAccess/List.tsx
Normal file
443
frontend/dashboard/src/pages/UserManagement/UserAccess/List.tsx
Normal file
@@ -0,0 +1,443 @@
|
||||
// @mui
|
||||
import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup, Pagination, Grid, Autocomplete, DialogActions } from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
// hooks
|
||||
import { Link, NavLink as RouterLink, useNavigate } from 'react-router-dom';
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import { UserAccess } from '../../../@types/user';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import { Delete, EditOutlined, FindInPageOutlined } from '@mui/icons-material';
|
||||
import MuiDialog from '@/components/MuiDialog';
|
||||
|
||||
export default function List() {
|
||||
const navigate = useNavigate();
|
||||
const { themeStretch } = useSettings();
|
||||
const { corporate_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? ''
|
||||
setSearchText(newSearchText);
|
||||
}
|
||||
|
||||
const handleSearchSubmit = (event: any) => {
|
||||
event.preventDefault();
|
||||
props.onSearch(searchText); // Trigger to Parent
|
||||
}
|
||||
|
||||
useEffect(() => { // Trigger First Search
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, [searchParams])
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '90%' }}>
|
||||
<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 handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleImportButton = () => {
|
||||
if (importForm?.current) {
|
||||
handleClose();
|
||||
importForm.current ? importForm.current.click() : console.log('No File selected');
|
||||
} else {
|
||||
alert('No file selected')
|
||||
}
|
||||
}
|
||||
|
||||
const handleICDList = async (appliedFilter = null) => {
|
||||
axios.get('master/diagnosis/list').then((response) => {
|
||||
const link = document.createElement('a');
|
||||
link.href = response.data.data.file_url;
|
||||
link.setAttribute('download', response.data.data.file_name);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
handleClose();
|
||||
});
|
||||
}
|
||||
|
||||
const handleCancelImportButton = () => {
|
||||
importForm.current.value = "";
|
||||
importForm.current.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
}
|
||||
|
||||
const handleImportChange = (event: any) => {
|
||||
if (event.target.files[0]) {
|
||||
setCurrentImportFileName(event.target.files[0].name)
|
||||
} else {
|
||||
setCurrentImportFileName(null);
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpload = () => {
|
||||
if (importForm.current?.files.length) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", importForm.current?.files[0])
|
||||
axios.post(`master/diagnosis/import`, formData )
|
||||
.then(response => {
|
||||
handleCancelImportButton();
|
||||
loadDataTableData();
|
||||
setImportResult(response.data)
|
||||
// alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
|
||||
})
|
||||
.catch(response => {
|
||||
enqueueSnackbar('Looks like something went wrong. Please check your data and try again. ' + response.message, { variant: 'error' })
|
||||
})
|
||||
} else {
|
||||
enqueueSnackbar('No File Selected', { variant: 'warning' })
|
||||
}
|
||||
}
|
||||
|
||||
const handleGetTemplate = (type :string) => {
|
||||
axios.get('corporates/import-document-example/' + type)
|
||||
.then((response) => {
|
||||
const link = document.createElement('a');
|
||||
link.href = response.data.data.file_url;
|
||||
link.setAttribute('download', response.data.data.file_name);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
handleClose();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input type='file' id='file' ref={importForm} style={{ display: 'none' }} onChange={handleImportChange} accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain" />
|
||||
{( !currentImportFileName && <Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter}/>
|
||||
{/* <h1>kjasndkjandskjasndkjansdkjansd</h1> */}
|
||||
<Button
|
||||
id="import-button"
|
||||
variant='contained'
|
||||
startIcon={<AddIcon />} sx={{ p: 1.8, width: '200px' }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
onClick={() => navigate(`/user-access/create`)}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
<Menu
|
||||
id="import-button"
|
||||
anchorEl={anchorEl}
|
||||
open={createMenu}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'basic-button',
|
||||
}}
|
||||
>
|
||||
<MenuItem>
|
||||
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Stack>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData( userAccess: UserAccess ): UserAccess {
|
||||
return {
|
||||
...userAccess,
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the every row of the table
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const handleActivate = (model: any, status: string) => {
|
||||
axios
|
||||
.put(`/master/diagnosis-template/${row.id}/activation`, {
|
||||
// service_code: service.service_code,
|
||||
active: status == 'active',
|
||||
})
|
||||
.then((res) => {
|
||||
setDataTableData({
|
||||
...dataTableData,
|
||||
data: dataTableData.data.map((model) => {
|
||||
let updatedModel = model;
|
||||
if (row.id == model.id) {
|
||||
updatedModel.active = res.data.icd.active;
|
||||
}
|
||||
return updatedModel;
|
||||
}),
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
// console.log('asdasd', error.response.data.message)
|
||||
enqueueSnackbar(
|
||||
error.response.data.message ?? error.message ?? 'Failed Processing Request',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: '1' } }}>
|
||||
<TableCell align="left"/>
|
||||
<TableCell align="left">{row.person?.name ?? '-'}</TableCell>
|
||||
<TableCell align="left">{row.email ?? '-'}</TableCell>
|
||||
<TableCell align="left">{row.role?.name ?? '-'}</TableCell>
|
||||
<TableCell align="center">
|
||||
<Stack direction="row" justifyContent="flex-end" spacing={1}>
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
{/* <MenuItem onClick={() => navigate(`/master/diagnosis/${row.id}`)}>
|
||||
<FindInPageOutlined />
|
||||
Detail
|
||||
</MenuItem> */}
|
||||
<MenuItem onClick={() => navigate(`/user/access/${row.id}/edit`)} >
|
||||
<EditOutlined />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => setOpenDialogDelete(true)}>
|
||||
<Delete color='error'/>
|
||||
Delete
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
// Delete
|
||||
const reasons = [
|
||||
{ value: 'agreement', label: 'Agreement changed' },
|
||||
{ value: 'endorsement', label: 'Endorsement' },
|
||||
{ value: 'renewal', label: 'Renewal' },
|
||||
{ value: 'wrong_setting', label: 'Wrong Setting' },
|
||||
// Add more options as needed
|
||||
];
|
||||
|
||||
const [isReasonSelected, setIsReasonSelected] = useState(false);
|
||||
const [formData, setFormData] = useState({
|
||||
reason: null
|
||||
});
|
||||
|
||||
const marginBottom2 = {
|
||||
marginBottom: 2,
|
||||
}
|
||||
|
||||
const style1 = {
|
||||
color: '#919EAB',
|
||||
width: '30%'
|
||||
}
|
||||
|
||||
const handleCloseDialog = () => {
|
||||
setOpenDialogDelete(false);
|
||||
resetForm();
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
setFormData({
|
||||
reason: null
|
||||
});
|
||||
};
|
||||
const handleChange = (field, value) => {
|
||||
setFormData((prevData) => ({
|
||||
...prevData,
|
||||
[field]: value,
|
||||
}));
|
||||
if (field === 'reason') {
|
||||
setIsReasonSelected(!!value);
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (isReasonSelected && formData.reason !== '') {
|
||||
alert('zsd.');
|
||||
} else {
|
||||
setIsReasonSelected(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Dialog
|
||||
const getContent = () => (
|
||||
<Stack spacing={1} marginTop={2}>
|
||||
<Typography variant="subtitle2">Are you sure to delete this User?</Typography>
|
||||
<Grid item xs={12} md={12} marginTop={4}>
|
||||
<Card sx={{padding:2, marginTop:2}} >
|
||||
<Stack direction='row' spacing={2} sx={marginBottom2}>
|
||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Reason*</Typography>
|
||||
<Autocomplete
|
||||
options={reasons}
|
||||
getOptionLabel={(option) => option.label}
|
||||
fullWidth
|
||||
value={reasons.find((r) => r.value === formData.reason) || null} // Use find to match the default value
|
||||
onChange={(e, newValue) => handleChange('reason', newValue?.value)}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Reason"
|
||||
variant="outlined"
|
||||
required
|
||||
error={!isReasonSelected} // Menandai input sebagai salah jika opsi tidak dipilih
|
||||
helperText={!isReasonSelected ? 'Alasan harus dipilih' : ''}
|
||||
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
<DialogActions>
|
||||
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialog}>Cancel</Button>
|
||||
<Button color="error" variant="contained" onClick={handleSubmit}>Delete</Button>
|
||||
</DialogActions>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||
const [dataTableLastRequest, setDataTableLastRequest] = useState(0);
|
||||
const [dataTableResponseState, setDataTableResponseState] = useState('idle');
|
||||
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>({
|
||||
current_page: 1,
|
||||
data: [],
|
||||
path: "",
|
||||
first_page_url: "",
|
||||
last_page: 1,
|
||||
last_page_url: "",
|
||||
next_page_url: "",
|
||||
prev_page_url: "",
|
||||
per_page: 10,
|
||||
from: 0,
|
||||
to: 0,
|
||||
total: 0
|
||||
});
|
||||
const [dataTablePage, setDataTablePage] = useState(5);
|
||||
|
||||
const loadDataTableData = async (appliedFilter : any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/user/access', { params: filter });
|
||||
console.log(response.data);
|
||||
setDataTableLoading(false);
|
||||
|
||||
setDataTableData(response.data);
|
||||
}
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const applyFilter = async (searchFilter: string) => {
|
||||
await loadDataTableData({ "search" : searchFilter });
|
||||
setSearchParams({ "search" : searchFilter });
|
||||
}
|
||||
|
||||
const handlePageChange = (event : ChangeEvent, value: number) => {
|
||||
const filter = Object.fromEntries([...searchParams.entries(), ["page", value]]);
|
||||
loadDataTableData(filter);
|
||||
setSearchParams(filter);
|
||||
}
|
||||
|
||||
const [openDialogDelete, setOpenDialogDelete] = React.useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<ImportForm />
|
||||
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper} sx={{ px: 1, mt: 3 }}>
|
||||
<Table aria-label="collapsible table">
|
||||
<colgroup>
|
||||
<col width="20" />
|
||||
<col width="250" />
|
||||
<col width="*" />
|
||||
<col width="50" />
|
||||
</colgroup>
|
||||
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="left" />
|
||||
<TableCell style={headStyle} align="left">Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">Email</TableCell>
|
||||
<TableCell style={headStyle} align="left">Role Access</TableCell>
|
||||
<TableCell style={headStyle} align="right"></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
{dataTableIsLoading ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={3} align="center">Loading</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
dataTableData.data.length == 0 ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={3} align="center">No Data</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataTableData.data.map(row => (
|
||||
<Row key={row.id} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange}/>
|
||||
<MuiDialog
|
||||
title={{name: "Delete User Access"}}
|
||||
openDialog={openDialogDelete}
|
||||
setOpenDialog={setOpenDialogDelete}
|
||||
content={getContent()}
|
||||
maxWidth="xs"
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import useSettings from "../../../hooks/useSettings";
|
||||
import {useContext, useEffect, useMemo, useState } from 'react';
|
||||
import axios from '../../../utils/axios';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import UserRoleForm from './Form';
|
||||
import { Role } from '../../../@types/user';
|
||||
import { Corporate } from "@/@types/corporates";
|
||||
import { ConfiguredCorporateContext } from "@/contexts/ConfiguredCorporateContext";
|
||||
|
||||
|
||||
|
||||
export default function PlanCreate() {
|
||||
const { themeStretch } = useSettings();
|
||||
const { corporate_id, id } = useParams();
|
||||
const [corporate, setCorporate] = useState<Corporate|null>();
|
||||
const configuredCorporateContext = useContext(ConfiguredCorporateContext);
|
||||
|
||||
useEffect(() => {
|
||||
setCorporate(configuredCorporateContext.currentCorporate);
|
||||
}, [configuredCorporateContext])
|
||||
|
||||
const [ currentUserRole, setCurrentUserRole ] = useState<Role>();
|
||||
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const isEdit = !!id;
|
||||
|
||||
const [permissions, setPermissions] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit) {
|
||||
axios.get('/user/role/'+id)
|
||||
.then((res) => {
|
||||
setCurrentUserRole(res.data);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.response.status === 404) {
|
||||
navigate('/404');
|
||||
}
|
||||
})
|
||||
}
|
||||
axios.get('/permission_list')
|
||||
.then((res) => {
|
||||
setPermissions(res.data);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.response && err.response.status === 404) {
|
||||
navigate('/404');
|
||||
} else {
|
||||
console.error('Error fetching permissions:', err);
|
||||
}
|
||||
});
|
||||
|
||||
}, [corporate_id, id]);
|
||||
|
||||
return (
|
||||
<Page title= "User Role">
|
||||
<HeaderBreadcrumbs
|
||||
sx={{ px: 2 }}
|
||||
heading={'User Role'}
|
||||
links={[
|
||||
{
|
||||
name: 'User Role',
|
||||
href: '/user-role',
|
||||
},
|
||||
{
|
||||
name: !isEdit ? 'Create' : 'Edit',
|
||||
href: '/corporate/'+corporate_id+'/divisions/'+id,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<UserRoleForm isEdit={isEdit} currentUserRole={currentUserRole} permissions={permissions}/>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
170
frontend/dashboard/src/pages/UserManagement/UserRole/Form.tsx
Normal file
170
frontend/dashboard/src/pages/UserManagement/UserRole/Form.tsx
Normal file
@@ -0,0 +1,170 @@
|
||||
import * as Yup from 'yup';
|
||||
import { LoadingButton } from "@mui/lab";
|
||||
import {Box, Card, FormControlLabel, Grid, Stack, Typography } from "@mui/material";
|
||||
import Autocomplete from '@mui/material/Autocomplete';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import { Role } from '../../../@types/user';
|
||||
import { Permisions } from '../../../@types/user';
|
||||
import { FormProvider, RHFSelect, RHFSwitch, RHFTextField } from "../../../components/hook-form";
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import axios from '../../../utils/axios';
|
||||
import palette from '@/theme/palette';
|
||||
import { Checkbox } from '@mui/material';
|
||||
import Label from '@/components/Label';
|
||||
|
||||
type Props = {
|
||||
isEdit: boolean;
|
||||
currentUserRole?: Role;
|
||||
permissions?: Permisions;
|
||||
};
|
||||
|
||||
export default function UserRoleForm({ isEdit, currentUserRole, permissions }: Props) {
|
||||
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
const navigate = useNavigate();
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const NewUserRoleSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
});
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
name: currentUserRole?.name || '',
|
||||
guard_name: currentUserRole?.guard_name || '',
|
||||
permission_check: currentUserRole?.permissions?.map(permission => permission.id) || []
|
||||
|
||||
}),
|
||||
[currentUserRole, permissions]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit && currentUserRole) {
|
||||
reset(defaultValues);
|
||||
}
|
||||
if (!isEdit) {
|
||||
reset(defaultValues);
|
||||
}
|
||||
}, [isEdit, currentUserRole]);
|
||||
|
||||
const methods = useForm({
|
||||
resolver: yupResolver(NewUserRoleSchema),
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
const {
|
||||
reset,
|
||||
watch,
|
||||
control,
|
||||
setValue,
|
||||
getValues,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
|
||||
const onSubmit = async (data: any) => {
|
||||
console.log(data, 'test1')
|
||||
if (!isEdit) {
|
||||
await axios
|
||||
.post('/user/role', data)
|
||||
.then((res) => {
|
||||
enqueueSnackbar('User Role created successfully', { variant: 'success' });
|
||||
})
|
||||
.then((res) => {
|
||||
navigate('/user-role', { replace: true });
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
if (response.status === 422) {
|
||||
for (const [key, value] of Object.entries(response.data.errors)) {
|
||||
setError(key, { message: value[0] });
|
||||
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
|
||||
}
|
||||
}
|
||||
else {
|
||||
enqueueSnackbar('Create Failed : '+ response.data.message, { variant: 'error' });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await axios
|
||||
.put('/user/role/' + currentUserRole?.id, data)
|
||||
.then((res) => {
|
||||
enqueueSnackbar('User Role updated successfully', { variant: 'success' });
|
||||
})
|
||||
.then((res) => {
|
||||
navigate('/user-role' , { replace: true });
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const guard_name_options = [
|
||||
{ value: '', label: '' },
|
||||
{ value: 'web', label: 'Primecenter' },
|
||||
{ value: 'client-portal', label: 'Client Portal' },
|
||||
{ value: 'hospital-portal', label: 'Hospital Portal' }
|
||||
];
|
||||
|
||||
// Buat fungsi handleCheckboxClick di luar komponen utama (UserRoleForm)
|
||||
const handleCheckboxClick = (permissionId, checked) => {
|
||||
const currentPermissions = getValues('permission_check') || [];
|
||||
if (checked) {
|
||||
setValue('permission_check', [...currentPermissions, permissionId]);
|
||||
} else {
|
||||
setValue('permission_check', currentPermissions.filter(id => id !== permissionId));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Box sx={{ px: 2 }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} sm={12}>
|
||||
<Card sx={{ px: 3, py: 4 }}>
|
||||
<Stack spacing={2}>
|
||||
<Typography variant="h6" color={palette.light.primary.main}>User Role</Typography>
|
||||
<RHFTextField name="name" label="Name" />
|
||||
<RHFSelect name="guard_name" label="Guard Name">
|
||||
{guard_name_options.map((option, index) => (
|
||||
<option key={index} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</RHFSelect>
|
||||
<Typography variant="h6" color={palette.light.primary.main}>Permission</Typography>
|
||||
<Grid container spacing={2}>
|
||||
{permissions?.map((permission, index) => (
|
||||
<Grid item xs={4} key={permission.id}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
name={`permission_check`}
|
||||
value={permission.id}
|
||||
checked={watch('permission_check')?.includes(permission.id) || false}
|
||||
onChange={(e) => handleCheckboxClick(permission.id, e.target.checked)}
|
||||
/>
|
||||
}
|
||||
label={permission.name}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
<LoadingButton type="submit" variant="contained" size="large" fullWidth={true} loading={isSubmitting}>
|
||||
{ isEdit? 'Update' : 'Create' }
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</FormProvider>
|
||||
|
||||
);
|
||||
}
|
||||
218
frontend/dashboard/src/pages/UserManagement/UserRole/History.tsx
Normal file
218
frontend/dashboard/src/pages/UserManagement/UserRole/History.tsx
Normal file
@@ -0,0 +1,218 @@
|
||||
// @mui
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
Collapse,
|
||||
Container,
|
||||
FormControl,
|
||||
Grid,
|
||||
IconButton,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
OutlinedInput,
|
||||
Paper,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
Badge,
|
||||
Stack,
|
||||
} from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import ArrowForwardIosSharpIcon from '@mui/icons-material/ArrowForwardIosSharp';
|
||||
import MuiAccordion, { AccordionProps } from '@mui/material/Accordion';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import MuiAccordionSummary, {
|
||||
AccordionSummaryProps,
|
||||
} from '@mui/material/AccordionSummary';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import axios from '../../../utils/axios';
|
||||
import { ConfiguredCorporateContext } from '@/contexts/ConfiguredCorporateContext';
|
||||
import MuiAccordionDetails from '@mui/material/AccordionDetails';
|
||||
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
|
||||
import { Corporate } from '@/@types/corporates';
|
||||
import { fDate, fDateTime } from '@/utils/formatTime';
|
||||
|
||||
const Accordion = styled((props: AccordionProps) => (
|
||||
<MuiAccordion disableGutters elevation={0} square {...props} />
|
||||
))(({ theme }) => ({
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
'&:not(:last-child)': {
|
||||
borderBottom: 0,
|
||||
},
|
||||
'&:before': {
|
||||
display: 'none',
|
||||
},
|
||||
}));
|
||||
|
||||
const AccordionSummary = styled((props: AccordionSummaryProps) => (
|
||||
<MuiAccordionSummary
|
||||
expandIcon={<ArrowForwardIosSharpIcon sx={{ fontSize: '0.9rem' }} />}
|
||||
{...props}
|
||||
/>
|
||||
))(({ theme }) => ({
|
||||
backgroundColor:
|
||||
theme.palette.mode === 'dark'
|
||||
? 'rgba(255, 255, 255, .05)'
|
||||
: 'rgba(0, 0, 0, .03)',
|
||||
flexDirection: 'row-reverse',
|
||||
'& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': {
|
||||
transform: 'rotate(90deg)',
|
||||
},
|
||||
'& .MuiAccordionSummary-content': {
|
||||
marginLeft: theme.spacing(1),
|
||||
},
|
||||
}));
|
||||
|
||||
const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({
|
||||
padding: theme.spacing(2),
|
||||
borderTop: '1px solid rgba(0, 0, 0, .125)',
|
||||
}));
|
||||
|
||||
export default function CustomizedAccordions() {
|
||||
const [expanded, setExpanded] = React.useState<string | false>('panel1');
|
||||
|
||||
const handleChange =
|
||||
(panel: string) => (event: React.SyntheticEvent, newExpanded: boolean) => {
|
||||
setExpanded(newExpanded ? panel : false);
|
||||
};
|
||||
const pageTitle = 'Diagnosis Template History';
|
||||
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { id } = useParams();
|
||||
|
||||
const [corporate, setCorporate] = useState<Corporate | null>();
|
||||
const [ currentCorporate, setCurrentCorporate ] = useState<Corporate>();
|
||||
|
||||
const configuredCorporateContext = useContext(ConfiguredCorporateContext);
|
||||
|
||||
useEffect(() => {
|
||||
setCorporate(configuredCorporateContext.currentCorporate);
|
||||
const model = 'App\\Models\\IcdTemplate';
|
||||
const url = `/audittrail/${id}?model=${model}`;
|
||||
axios.get(url)
|
||||
.then((res) => {
|
||||
setCurrentCorporate(res.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Terjadi kesalahan:', error);
|
||||
});
|
||||
|
||||
}, [configuredCorporateContext]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<HeaderBreadcrumbs
|
||||
heading={pageTitle}
|
||||
links={[
|
||||
{
|
||||
name: 'Master',
|
||||
href: '/master/diagnosis-template',
|
||||
},
|
||||
{
|
||||
name: 'Diagnosis Template',
|
||||
href: '/master/diagnosis-template',
|
||||
},
|
||||
// {
|
||||
// name: 'Audittrail ICD',
|
||||
// href: '/corporate/' + id + '/plans',
|
||||
// },
|
||||
]}
|
||||
/>
|
||||
{currentCorporate?.data.map((item, index) => (
|
||||
<Accordion
|
||||
key={index}
|
||||
expanded={expanded === `panel${index}`}
|
||||
onChange={handleChange(`panel${index}`)}
|
||||
>
|
||||
<AccordionSummary
|
||||
aria-controls={`panel${index}d-content`}
|
||||
id={`panel${index}d-header`}
|
||||
>
|
||||
<Typography>{`Data has ${item.action} by ${item.user_id} on ${fDateTime(item.updated_at)}`}</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="center">Field</TableCell>
|
||||
<TableCell align="center">Old Value</TableCell>
|
||||
<TableCell align="center">New Values</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{Object.entries(item.old_values).map(([key, value]) => {
|
||||
let renderedValue;
|
||||
if (key === 'deleted_by' ||
|
||||
key === 'deleted_at' ||
|
||||
key === 'created_by' ||
|
||||
key === 'created_at' ||
|
||||
key === 'updated_by' ||
|
||||
key === 'description'
|
||||
) {
|
||||
return null; // Melewati iterasi saat key adalah 'deleted_by'
|
||||
}
|
||||
switch (key) {
|
||||
case 'welcome_message':
|
||||
renderedValue = item.new_values[key].replace(/<[^>]*>/g, '');
|
||||
value = value.replace(/<[^>]*>/g, '');
|
||||
break;
|
||||
case 'help_text':
|
||||
renderedValue = item.new_values[key].replace(/<[^>]*>/g, '');
|
||||
value = value.replace(/<[^>]*>/g, '');
|
||||
break;
|
||||
case 'active':
|
||||
renderedValue = item.new_values[key] == 1 ? 'Active' : 'Inactive';
|
||||
value = value == 1 ? 'Active' : 'Inactive';
|
||||
break;
|
||||
case 'created_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
case 'updated_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
case 'updated_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
case 'delete_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
default:
|
||||
renderedValue = item.new_values[key];
|
||||
break;
|
||||
}
|
||||
|
||||
const field = key.charAt(0).toUpperCase() + key.slice(1);
|
||||
if (value == renderedValue) {
|
||||
return null
|
||||
} else {
|
||||
return (
|
||||
<TableRow key={key} sx={{ '&:last-child td, &:last-child th': { border: 0 } }}>
|
||||
<TableCell>{`${field}`}</TableCell>
|
||||
<TableCell align="center">{`${value}`}</TableCell>
|
||||
<TableCell align="center">{renderedValue}</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
})}
|
||||
|
||||
</TableBody>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Card, Grid } from "@mui/material";
|
||||
import { useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import useSettings from "../../../hooks/useSettings";
|
||||
import List from "./List";
|
||||
|
||||
|
||||
|
||||
export default function Divisions() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const pageTitle = 'User Role';
|
||||
return (
|
||||
<Page title={ pageTitle }>
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
sx={{ px: 2 }}
|
||||
heading={ pageTitle }
|
||||
links={[
|
||||
{
|
||||
name: 'User Role',
|
||||
// href: '/master/diagnosis',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<List />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
442
frontend/dashboard/src/pages/UserManagement/UserRole/List.tsx
Normal file
442
frontend/dashboard/src/pages/UserManagement/UserRole/List.tsx
Normal file
@@ -0,0 +1,442 @@
|
||||
// @mui
|
||||
import { Box, Button, Card, MenuItem, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Stack, Menu, Grid, DialogActions } from '@mui/material';
|
||||
import { Autocomplete } from "@mui/material";
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
// hooks
|
||||
import { Link, NavLink as RouterLink, useNavigate } from 'react-router-dom';
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import { Role } from '../../../@types/user';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import { Delete, EditOutlined, FindInPageOutlined } from '@mui/icons-material';
|
||||
import MuiDialog from '@/components/MuiDialog';
|
||||
|
||||
export default function List() {
|
||||
const navigate = useNavigate();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? ''
|
||||
setSearchText(newSearchText);
|
||||
}
|
||||
|
||||
const handleSearchSubmit = (event: any) => {
|
||||
event.preventDefault();
|
||||
props.onSearch(searchText); // Trigger to Parent
|
||||
}
|
||||
|
||||
useEffect(() => { // Trigger First Search
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, [searchParams])
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '90%' }}>
|
||||
<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 handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleImportButton = () => {
|
||||
if (importForm?.current) {
|
||||
handleClose();
|
||||
importForm.current ? importForm.current.click() : console.log('No File selected');
|
||||
} else {
|
||||
alert('No file selected')
|
||||
}
|
||||
}
|
||||
|
||||
const handleICDList = async (appliedFilter = null) => {
|
||||
axios.get('master/diagnosis/list').then((response) => {
|
||||
const link = document.createElement('a');
|
||||
link.href = response.data.data.file_url;
|
||||
link.setAttribute('download', response.data.data.file_name);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
handleClose();
|
||||
});
|
||||
}
|
||||
|
||||
const handleCancelImportButton = () => {
|
||||
importForm.current.value = "";
|
||||
importForm.current.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
}
|
||||
|
||||
const handleImportChange = (event: any) => {
|
||||
if (event.target.files[0]) {
|
||||
setCurrentImportFileName(event.target.files[0].name)
|
||||
} else {
|
||||
setCurrentImportFileName(null);
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpload = () => {
|
||||
if (importForm.current?.files.length) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", importForm.current?.files[0])
|
||||
axios.post(`master/diagnosis/import`, formData )
|
||||
.then(response => {
|
||||
handleCancelImportButton();
|
||||
loadDataTableData();
|
||||
setImportResult(response.data)
|
||||
// alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
|
||||
})
|
||||
.catch(response => {
|
||||
enqueueSnackbar('Looks like something went wrong. Please check your data and try again. ' + response.message, { variant: 'error' })
|
||||
})
|
||||
} else {
|
||||
enqueueSnackbar('No File Selected', { variant: 'warning' })
|
||||
}
|
||||
}
|
||||
|
||||
const handleGetTemplate = (type :string) => {
|
||||
axios.get('corporates/import-document-example/' + type)
|
||||
.then((response) => {
|
||||
const link = document.createElement('a');
|
||||
link.href = response.data.data.file_url;
|
||||
link.setAttribute('download', response.data.data.file_name);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
handleClose();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input type='file' id='file' ref={importForm} style={{ display: 'none' }} onChange={handleImportChange} accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain" />
|
||||
{( !currentImportFileName && <Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter}/>
|
||||
{/* <h1>kjasndkjandskjasndkjansdkjansd</h1> */}
|
||||
<Button
|
||||
id="import-button"
|
||||
variant='contained'
|
||||
startIcon={<AddIcon />} sx={{ p: 1.8, width: '200px' }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
onClick={() => navigate(`/user-role/create`)}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
<Menu
|
||||
id="import-button"
|
||||
anchorEl={anchorEl}
|
||||
open={createMenu}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'basic-button',
|
||||
}}
|
||||
>
|
||||
<MenuItem>
|
||||
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Stack>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData( userManamgent: Role ): Role {
|
||||
return {
|
||||
...userManamgent,
|
||||
}
|
||||
}
|
||||
|
||||
const [id, setId] = useState(null)
|
||||
|
||||
// Generate the every row of the table
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const handleActivate = (model: any, status: string) => {
|
||||
axios
|
||||
.put(`/master/diagnosis-template/${row.id}/activation`, {
|
||||
// service_code: service.service_code,
|
||||
active: status == 'active',
|
||||
})
|
||||
.then((res) => {
|
||||
setDataTableData({
|
||||
...dataTableData,
|
||||
data: dataTableData.data.map((model) => {
|
||||
let updatedModel = model;
|
||||
if (row.id == model.id) {
|
||||
updatedModel.active = res.data.icd.active;
|
||||
}
|
||||
return updatedModel;
|
||||
}),
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
// console.log('asdasd', error.response.data.message)
|
||||
enqueueSnackbar(
|
||||
error.response.data.message ?? error.message ?? 'Failed Processing Request',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: '1' } }}>
|
||||
<TableCell align="left"/>
|
||||
<TableCell align="left">{row.id}</TableCell>
|
||||
<TableCell align="left">{row.name ?? '-'}</TableCell>
|
||||
<TableCell align="left">{row.guard_name ?? '-'}</TableCell>
|
||||
<TableCell align="center">
|
||||
<Stack direction="row" justifyContent="flex-end" spacing={1}>
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
{/* <MenuItem onClick={() => navigate(`/user/role/${row.id}`)}>
|
||||
<FindInPageOutlined />
|
||||
Detail
|
||||
</MenuItem> */}
|
||||
<MenuItem onClick={() => navigate(`/user/role/${row.id}/edit`)} >
|
||||
<EditOutlined />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => { setOpenDialogDelete(true); setId(row.id); }}>
|
||||
<Delete color='error'/>
|
||||
Delete
|
||||
</MenuItem>
|
||||
{/* <MenuItem onClick={() => navigate(`/user/role/${row.id}/history`)}>
|
||||
<HistoryIcon />
|
||||
History
|
||||
</MenuItem> */}
|
||||
</>
|
||||
} />
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
// Delete
|
||||
const reasons = [
|
||||
{ value: 'agreement', label: 'Agreement changed' },
|
||||
{ value: 'endorsement', label: 'Endorsement' },
|
||||
{ value: 'renewal', label: 'Renewal' },
|
||||
{ value: 'wrong_setting', label: 'Wrong Setting' },
|
||||
// Add more options as needed
|
||||
];
|
||||
|
||||
const [isReasonSelected, setIsReasonSelected] = useState(false);
|
||||
const [formData, setFormData] = useState({
|
||||
reason: null
|
||||
});
|
||||
|
||||
const marginBottom2 = {
|
||||
marginBottom: 2,
|
||||
}
|
||||
|
||||
const style1 = {
|
||||
color: '#919EAB',
|
||||
width: '30%'
|
||||
}
|
||||
|
||||
const handleCloseDialog = () => {
|
||||
setOpenDialogDelete(false);
|
||||
resetForm();
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
setFormData({
|
||||
reason: null
|
||||
});
|
||||
};
|
||||
|
||||
const handleChange = (field, value) => {
|
||||
setFormData((prevData) => ({
|
||||
...prevData,
|
||||
[field]: value,
|
||||
}));
|
||||
if (field === 'reason') {
|
||||
setIsReasonSelected(!!value);
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (isReasonSelected && formData.reason !== '') {
|
||||
console.log(formData, 'test')
|
||||
} else {
|
||||
setIsReasonSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Dialog
|
||||
const getContent = () => (
|
||||
<Stack spacing={1} marginTop={2}>
|
||||
<Typography variant="subtitle2">Are you sure to delete this User Role?</Typography>
|
||||
<Grid item xs={12} md={12} marginTop={4}>
|
||||
<Card sx={{padding:2, marginTop:2}} >
|
||||
<Stack direction='row' spacing={2} sx={marginBottom2}>
|
||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Reason*</Typography>
|
||||
<Autocomplete
|
||||
options={reasons}
|
||||
getOptionLabel={(option) => option.label}
|
||||
fullWidth
|
||||
value={reasons.find((r) => r.value === formData.reason) || null} // Use find to match the default value
|
||||
onChange={(e, newValue) => handleChange('reason', newValue?.value)}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Reason"
|
||||
variant="outlined"
|
||||
required
|
||||
error={!isReasonSelected} // Menandai input sebagai salah jika opsi tidak dipilih
|
||||
helperText={!isReasonSelected ? 'Alasan harus dipilih' : ''}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
<DialogActions>
|
||||
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialog}>Cancel</Button>
|
||||
<Button color="error" variant="contained" onClick={handleSubmit}>Delete</Button>
|
||||
</DialogActions>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||
const [dataTableLastRequest, setDataTableLastRequest] = useState(0);
|
||||
const [dataTableResponseState, setDataTableResponseState] = useState('idle');
|
||||
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>({
|
||||
current_page: 1,
|
||||
data: [],
|
||||
path: "",
|
||||
first_page_url: "",
|
||||
last_page: 1,
|
||||
last_page_url: "",
|
||||
next_page_url: "",
|
||||
prev_page_url: "",
|
||||
per_page: 10,
|
||||
from: 0,
|
||||
to: 0,
|
||||
total: 0
|
||||
});
|
||||
const [dataTablePage, setDataTablePage] = useState(5);
|
||||
|
||||
const loadDataTableData = async (appliedFilter : any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/user/role', { params: filter });
|
||||
console.log(response.data);
|
||||
setDataTableLoading(false);
|
||||
|
||||
setDataTableData(response.data);
|
||||
}
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const applyFilter = async (searchFilter: string) => {
|
||||
await loadDataTableData({ "search" : searchFilter });
|
||||
setSearchParams({ "search" : searchFilter });
|
||||
}
|
||||
|
||||
const handlePageChange = (event : ChangeEvent, value: number) => {
|
||||
const filter = Object.fromEntries([...searchParams.entries(), ["page", value]]);
|
||||
loadDataTableData(filter);
|
||||
setSearchParams(filter);
|
||||
}
|
||||
|
||||
const [openDialogDelete, setOpenDialogDelete] = React.useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<ImportForm />
|
||||
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper} sx={{ px: 1, mt: 3 }}>
|
||||
<Table aria-label="collapsible table">
|
||||
<colgroup>
|
||||
<col width="20" />
|
||||
<col width="250" />
|
||||
<col width="*" />
|
||||
<col width="50" />
|
||||
</colgroup>
|
||||
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="left" />
|
||||
<TableCell style={headStyle} align="left">ID</TableCell>
|
||||
<TableCell style={headStyle} align="left">Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">Guard Name</TableCell>
|
||||
<TableCell style={headStyle} align="left"></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
{dataTableIsLoading ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={3} align="center">Loading</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
dataTableData.data.length == 0 ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={3} align="center">No Data</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataTableData.data.map(row => (
|
||||
<Row key={row.id} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange}/>
|
||||
|
||||
<MuiDialog
|
||||
title={{name: "Delete User Role"}}
|
||||
openDialog={openDialogDelete}
|
||||
setOpenDialog={setOpenDialogDelete}
|
||||
content={getContent()}
|
||||
maxWidth="xs"
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -523,6 +523,34 @@ export default function Router() {
|
||||
path: 'e-prescription/live-chat/:id/show',
|
||||
element: <EPrescriptionShow />,
|
||||
},
|
||||
{
|
||||
path: 'user-role',
|
||||
element: <UserRole />,
|
||||
},
|
||||
{
|
||||
path: 'user-role/create',
|
||||
element: <UserRoleCreate />,
|
||||
},
|
||||
{
|
||||
path: 'user/role/:id/edit',
|
||||
element: <UserRoleCreate />,
|
||||
},
|
||||
{
|
||||
path: 'user-access',
|
||||
element: <UserAccess />,
|
||||
},
|
||||
{
|
||||
path: 'user-access/create',
|
||||
element: <UserAccessCreate />,
|
||||
},
|
||||
{
|
||||
path: 'user/access/:id/edit',
|
||||
element: <UserAccessCreate />,
|
||||
},
|
||||
// {
|
||||
// path: 'e-prescription/live-chat/:id/show',
|
||||
// element: <EPrescriptionShow />,
|
||||
// },
|
||||
],
|
||||
},
|
||||
// {
|
||||
@@ -653,9 +681,6 @@ const RequestLogDetail = Loadable(lazy(() => import('../pages/CustomerService/R
|
||||
const FinalLog = Loadable(lazy(() => import('../pages/CustomerService/FinalLog/Index')))
|
||||
const FinalLogDetail = Loadable(lazy(() => import('../pages/CustomerService/FinalLog/Detail')))
|
||||
|
||||
|
||||
|
||||
|
||||
const MasterDiagnosisTemplate = Loadable(lazy(() => import('../pages/Master/Diagnosis/Master/Index')));
|
||||
const MasterDiagnosisTemplateCreate = Loadable(lazy(() => import('../pages/Master/Diagnosis/Master/CreateUpdate')));
|
||||
const MasterDiagnosisTemplateHistories = Loadable(
|
||||
@@ -733,3 +758,9 @@ const ClaimRequestsDetail = Loadable(lazy(() => import('../pages/ClaimRequests/D
|
||||
|
||||
|
||||
const Membership = Loadable(lazy(() => import('../pages/Service/Membership/index')));
|
||||
|
||||
// User Management
|
||||
const UserRole = Loadable(lazy(() => import('../pages/UserManagement/UserRole/Index')));
|
||||
const UserRoleCreate = Loadable(lazy(() => import('../pages/UserManagement/UserRole/CreateUpdate')));
|
||||
const UserAccess = Loadable(lazy(() => import('../pages/UserManagement/UserAccess/Index')));
|
||||
const UserAccessCreate = Loadable(lazy(() => import('../pages/UserManagement/UserAccess/CreateUpdate')));
|
||||
|
||||
Reference in New Issue
Block a user