Merge remote-tracking branch 'origin/staging' into origin/production
This commit is contained in:
@@ -296,7 +296,9 @@ class ClaimController extends Controller
|
|||||||
'Excess Paid',
|
'Excess Paid',
|
||||||
'Diagnosis',
|
'Diagnosis',
|
||||||
'Keterangan',
|
'Keterangan',
|
||||||
'Catatan'
|
'Catatan',
|
||||||
|
'Invoice No',
|
||||||
|
'Billing No'
|
||||||
];
|
];
|
||||||
$style = (new StyleBuilder())
|
$style = (new StyleBuilder())
|
||||||
->setFontBold()
|
->setFontBold()
|
||||||
@@ -336,7 +338,9 @@ class ClaimController extends Controller
|
|||||||
DB::raw('
|
DB::raw('
|
||||||
(Select SUM(request_log_benefits.amount_approved) as tot_bill FROM request_log_benefits
|
(Select SUM(request_log_benefits.amount_approved) as tot_bill FROM request_log_benefits
|
||||||
WHERE request_log_benefits.request_log_id = request_logs.id AND request_log_benefits.deleted_at IS NULL LIMIT 1) AS tot_bill
|
WHERE request_log_benefits.request_log_id = request_logs.id AND request_log_benefits.deleted_at IS NULL LIMIT 1) AS tot_bill
|
||||||
')
|
'),
|
||||||
|
'request_logs.invoice_no',
|
||||||
|
'request_logs.billing_no',
|
||||||
)
|
)
|
||||||
->groupBy(
|
->groupBy(
|
||||||
'request_logs.submission_date',
|
'request_logs.submission_date',
|
||||||
@@ -509,6 +513,8 @@ class ClaimController extends Controller
|
|||||||
!empty($item->diagnosis) ? $item->diagnosis : '',
|
!empty($item->diagnosis) ? $item->diagnosis : '',
|
||||||
!empty($item->keterangan) ? $item->keterangan : '',
|
!empty($item->keterangan) ? $item->keterangan : '',
|
||||||
!empty($item->catatan) ? $item->catatan : '',
|
!empty($item->catatan) ? $item->catatan : '',
|
||||||
|
!empty($item->invoice_no) ? $item->invoice_no : '',
|
||||||
|
!empty($item->billing_no) ? $item->billing_no : '',
|
||||||
|
|
||||||
];
|
];
|
||||||
array_push($dataRow,$rowData);
|
array_push($dataRow,$rowData);
|
||||||
@@ -543,6 +549,8 @@ class ClaimController extends Controller
|
|||||||
'',
|
'',
|
||||||
'',
|
'',
|
||||||
'',
|
'',
|
||||||
|
!empty($item->invoice_no) ? $item->invoice_no : '',
|
||||||
|
!empty($item->billing_no) ? $item->billing_no : '',
|
||||||
|
|
||||||
];
|
];
|
||||||
array_push($dataRow,$rowData);
|
array_push($dataRow,$rowData);
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ use Modules\Internal\Http\Controllers\ClaimEncounterController;
|
|||||||
use Modules\Client\Http\Controllers\Api\ClaimReportController;
|
use Modules\Client\Http\Controllers\Api\ClaimReportController;
|
||||||
use Modules\Client\Http\Controllers\Api\ClaimRequestController;
|
use Modules\Client\Http\Controllers\Api\ClaimRequestController;
|
||||||
use Modules\Client\Http\Controllers\Api\DataController;
|
use Modules\Client\Http\Controllers\Api\DataController;
|
||||||
|
use Modules\Internal\Http\Controllers\Api\FormulariumController;
|
||||||
|
use Modules\Internal\Http\Controllers\Api\FormulariumTemplateController;
|
||||||
|
use Modules\Internal\Http\Controllers\Api\AuditTrailController;
|
||||||
|
use Modules\Internal\Http\Controllers\Api\CorporateController;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -71,5 +75,20 @@ Route::prefix('client')->group(function () {
|
|||||||
|
|
||||||
Route::post('claim-requests', [ClaimRequestController::class, 'store'])->name('claim-requests.store');
|
Route::post('claim-requests', [ClaimRequestController::class, 'store'])->name('claim-requests.store');
|
||||||
Route::post('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show');
|
Route::post('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show');
|
||||||
|
|
||||||
|
Route::get('master/formulariums/{formulariums_template_id}', [FormulariumController::class, 'index']);
|
||||||
|
Route::post('master/formulariums/{formulariums_template_id}', [FormulariumController::class, 'store']);
|
||||||
|
Route::post('master/formulariums/{formulariums_template_id}/import', [FormulariumController::class, 'import']);
|
||||||
|
Route::get('master/formulariums/{formulariums_template_id}/list', [FormulariumController::class, 'generateFormulariumList']);
|
||||||
|
|
||||||
|
Route::get('master/formularium-template', [FormulariumTemplateController::class, 'index']);
|
||||||
|
Route::get('master/formularium-template/search', [FormulariumTemplateController::class, 'search']);
|
||||||
|
Route::post('master/formularium-template/store', [FormulariumTemplateController::class, 'store']);
|
||||||
|
Route::put('master/formularium-template/{id}/activation', [FormulariumTemplateController::class, 'activation']);
|
||||||
|
Route::get('master/formularium-template/{id}/edit', [FormulariumTemplateController::class, 'edit']);
|
||||||
|
Route::put('master/formularium-template/{id}/update', [FormulariumTemplateController::class, 'update']);
|
||||||
|
|
||||||
|
Route::get('audittrail/{corporate_id}', [AuditTrailController::class, 'index']);
|
||||||
|
Route::get('corporates/import-document-example/{document_type}', [CorporateController::class, 'importDocumentExample']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ use Modules\Internal\Transformers\RequestLogResource;
|
|||||||
|
|
||||||
use App\Models\RequestLog;
|
use App\Models\RequestLog;
|
||||||
|
|
||||||
|
use ZipArchive;
|
||||||
|
use File;
|
||||||
|
|
||||||
use PDF;
|
use PDF;
|
||||||
|
|
||||||
class ClaimController extends Controller
|
class ClaimController extends Controller
|
||||||
@@ -122,6 +125,96 @@ class ClaimController extends Controller
|
|||||||
return response()->json(Helper::paginateResources($results));
|
return response()->json(Helper::paginateResources($results));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function filesProvider(Request $request)
|
||||||
|
{
|
||||||
|
$limit = $request->has('per_page') ? $request->input('per_page') : 50;
|
||||||
|
$results = DB::table('request_logs')
|
||||||
|
->leftJoin('members', 'request_logs.member_id', '=', 'members.id')
|
||||||
|
->join('files', 'request_logs.id', '=', 'files.fileable_id')
|
||||||
|
// ->leftJoin('member_plans', 'member_plans.member_id', '=', 'members.id')
|
||||||
|
->when($request->input('search'), function ($query, $search) {
|
||||||
|
$query->where(function ($query) use ($search) {
|
||||||
|
$query->orWhere('members.name', 'like', "%" . $search . "%");
|
||||||
|
$query->orWhere('request_logs.code', 'like', "%" . $search . "%");
|
||||||
|
$query->orWhere('members.member_id', 'like', "%" . $search . "%");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->when($request->has('orderBy'), function ($query) use ($request) {
|
||||||
|
$orderBy = $request->orderBy;
|
||||||
|
$direction = $request->order ?? 'asc';
|
||||||
|
|
||||||
|
$query->orderBy($orderBy, $direction);
|
||||||
|
})
|
||||||
|
->when($request->input('start_date') , function ($query, $start_date) {
|
||||||
|
$query->where(function ($query) use ($start_date) {
|
||||||
|
$query->where('request_logs.created_at', '>=', $start_date. ' 00:00:00');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->when($request->input('end_date') , function ($query, $end_date) {
|
||||||
|
$query->where(function ($query) use ($end_date) {
|
||||||
|
$query->where('request_logs.created_at', '<=', $end_date. ' 23:59:59');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->when($request->input('provider') , function ($query, $provider) {
|
||||||
|
$query->where(function ($query) use ($provider) {
|
||||||
|
$query->where('request_logs.organization_id', '=', $provider);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->where('files.fileable_type', '=', 'App\Models\RequestLog')
|
||||||
|
->where('request_logs.final_log', '=', '1')
|
||||||
|
->where('request_logs.status_final_log', '=', 'approved')
|
||||||
|
->select(
|
||||||
|
'files.original_name as files',
|
||||||
|
'files.id',
|
||||||
|
'files.id AS id_log',
|
||||||
|
'request_logs.code as code',
|
||||||
|
'members.name',
|
||||||
|
'request_logs.created_at',
|
||||||
|
DB::raw('
|
||||||
|
(SELECT organizations.name FROM organizations WHERE organizations.id = request_logs.organization_id LIMIT 1) AS provider
|
||||||
|
'),
|
||||||
|
'request_logs.status_final_log as status',
|
||||||
|
DB::raw("CONCAT('" . env('APP_URL') . "/storage/', path) as path")
|
||||||
|
)
|
||||||
|
->paginate($limit);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return response()->json(Helper::paginateResources($results));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadZip(Request $request)
|
||||||
|
{
|
||||||
|
$selectedRows = $request->selectedRows; // asumsi $selectedRows berisi array ID file yang dipilih
|
||||||
|
$files = [];
|
||||||
|
|
||||||
|
// Ambil path file dari database atau sumber lain sesuai dengan $selectedRows
|
||||||
|
$data = DB::table('files')
|
||||||
|
->whereIn('id', $selectedRows)
|
||||||
|
->select('path')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
foreach ($data as $value) {
|
||||||
|
$files[] = storage_path('app/public/' . $value->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$zipFileName = 'downloaded_files.zip';
|
||||||
|
$zip = new ZipArchive();
|
||||||
|
|
||||||
|
if ($zip->open(storage_path('app/public/' . $zipFileName), ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$zip->addFile($file, basename($file));
|
||||||
|
}
|
||||||
|
|
||||||
|
$zip->close();
|
||||||
|
|
||||||
|
// Mengembalikan response berupa URL file zip
|
||||||
|
return response()->json(['file_url' => env('APP_URL').Storage::url($zipFileName)], 200);
|
||||||
|
} else {
|
||||||
|
return response()->json(['message' => 'Gagal membuat file ZIP.'], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function downloadTemplate()
|
public function downloadTemplate()
|
||||||
{
|
{
|
||||||
return Helper::responseJson([
|
return Helper::responseJson([
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace Modules\Internal\Http\Controllers\Api;
|
namespace Modules\Internal\Http\Controllers\Api;
|
||||||
|
|
||||||
use App\Models\Drug;
|
use App\Models\Drug;
|
||||||
|
use App\Models\Unit;
|
||||||
use Illuminate\Contracts\Support\Renderable;
|
use Illuminate\Contracts\Support\Renderable;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Routing\Controller;
|
use Illuminate\Routing\Controller;
|
||||||
@@ -25,6 +26,37 @@ class DrugController extends Controller
|
|||||||
return $drugs;
|
return $drugs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function drugList(Request $request){
|
||||||
|
$drugs = Drug::query()
|
||||||
|
->where([
|
||||||
|
'atc_code' => 'lms', // ini untuk menggunakan list obat yang baru
|
||||||
|
])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$manipulatedDrugs = $drugs->map(function ($drug) {
|
||||||
|
// Contoh manipulasi, tambahkan atau ubah properti sesuai kebutuhan
|
||||||
|
return [
|
||||||
|
'value' => $drug->id, // Ganti dengan properti yang sesuai dari model Icd
|
||||||
|
'label' => $drug->name, // Ganti dengan properti yang sesuai dari model Icd
|
||||||
|
];
|
||||||
|
});
|
||||||
|
return Helper::responseJson(data: $manipulatedDrugs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unitList(Request $request){
|
||||||
|
$units = Unit::query()
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$manipulatedUnits = $units->map(function ($unit) {
|
||||||
|
// Contoh manipulasi, tambahkan atau ubah properti sesuai kebutuhan
|
||||||
|
return [
|
||||||
|
'value' => $unit->id, // Ganti dengan properti yang sesuai dari model Icd
|
||||||
|
'label' => $unit->name, // Ganti dengan properti yang sesuai dari model Icd
|
||||||
|
];
|
||||||
|
});
|
||||||
|
return Helper::responseJson(data: $manipulatedUnits);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the form for creating a new resource.
|
* Show the form for creating a new resource.
|
||||||
* @return Renderable
|
* @return Renderable
|
||||||
@@ -123,20 +155,22 @@ class DrugController extends Controller
|
|||||||
|
|
||||||
foreach ($processedData as $row) {
|
foreach ($processedData as $row) {
|
||||||
try {
|
try {
|
||||||
Drug::create(
|
Drug::updateOrCreate([
|
||||||
[
|
'code' => $row['code'],
|
||||||
'name' => $row['name'],
|
],
|
||||||
'code' => $row['code'],
|
[
|
||||||
'generic_name' => $row['generic_name'],
|
'name' => $row['name'],
|
||||||
'description' => $row['description'],
|
'code' => $row['code'],
|
||||||
'mims_class' => $row['mims_class'],
|
'generic_name' => $row['generic_name'],
|
||||||
'indications' => $row['indications'],
|
'description' => $row['description'],
|
||||||
'atc_code' => $row['atc_code'],
|
'mims_class' => $row['mims_class'],
|
||||||
'segmentation' => $row['segmentation'],
|
'indications' => $row['indications'],
|
||||||
'type' => $row['type'],
|
'atc_code' => $row['atc_code'],
|
||||||
'dosage' => $row['dosage'],
|
'segmentation' => $row['segmentation'],
|
||||||
'remark' => $row['remark'],
|
'type' => $row['type'],
|
||||||
]
|
'dosage' => $row['dosage'],
|
||||||
|
'remark' => $row['remark'],
|
||||||
|
]
|
||||||
);
|
);
|
||||||
$importedRows++;
|
$importedRows++;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
|||||||
@@ -24,20 +24,44 @@ use Modules\Internal\Services\IcdService;
|
|||||||
class FormulariumTemplateController extends Controller
|
class FormulariumTemplateController extends Controller
|
||||||
{
|
{
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{ if($request->corporate_id)
|
||||||
if ($request->search){
|
{
|
||||||
return FormulariumTemplate::when($request->search ?? null, function($icd, $search) {
|
if ($request->search){
|
||||||
$icd->where('name', 'LIKE', '%'.$search.'%')
|
return FormulariumTemplate::when($request->search ?? null, function($icd, $search) {
|
||||||
->orWhere('description', 'LIKE', '%'.$search.'%');
|
$icd->where('name', 'LIKE', '%'.$search.'%')
|
||||||
})->paginate(15);
|
->orWhere('description', 'LIKE', '%'.$search.'%');
|
||||||
} else {
|
})
|
||||||
$diagnosisTemplate = FormulariumTemplate::query()
|
->join('corporate_formulariums', 'formularium_templates.id', '=', 'corporate_formulariums.formularium_template_id')
|
||||||
// ->filter($request->toArray())
|
->where('corporate_formulariums.corporate_id', '=', $request->corporate_id)
|
||||||
->orderBy('name', 'ASC')
|
->select('formularium_templates.*', 'corporate_formulariums.corporate_id')
|
||||||
->paginate(15);
|
->orderBy('formularium_templates.id', 'ASC')
|
||||||
return $diagnosisTemplate;
|
->paginate(15);
|
||||||
|
} else {
|
||||||
|
$diagnosisTemplate = FormulariumTemplate::query()
|
||||||
|
// ->filter($request->toArray())
|
||||||
|
->join('corporate_formulariums', 'formularium_templates.id', '=', 'corporate_formulariums.formularium_template_id')
|
||||||
|
->where('corporate_formulariums.corporate_id', '=', $request->corporate_id)
|
||||||
|
->select('formularium_templates.*', 'corporate_formulariums.corporate_id')
|
||||||
|
->orderBy('formularium_templates.id', 'ASC')
|
||||||
|
->paginate(15);
|
||||||
|
return $diagnosisTemplate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($request->search){
|
||||||
|
return FormulariumTemplate::when($request->search ?? null, function($icd, $search) {
|
||||||
|
$icd->where('name', 'LIKE', '%'.$search.'%')
|
||||||
|
->orWhere('description', 'LIKE', '%'.$search.'%');
|
||||||
|
})->paginate(15);
|
||||||
|
} else {
|
||||||
|
$diagnosisTemplate = FormulariumTemplate::query()
|
||||||
|
// ->filter($request->toArray())
|
||||||
|
->orderBy('name', 'ASC')
|
||||||
|
->paginate(15);
|
||||||
|
return $diagnosisTemplate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,11 +2,36 @@
|
|||||||
|
|
||||||
namespace Modules\Internal\Http\Controllers\Api;
|
namespace Modules\Internal\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use App\Models\OLDLMS\Livechat;
|
||||||
|
use App\Models\OLDLMS\LivechatSummary;
|
||||||
|
use App\Models\OLDLMS\Appointment;
|
||||||
|
use App\Models\OLDLMS\Dokter;
|
||||||
|
use App\Models\OLDLMS\User;
|
||||||
|
use App\Models\OLDLMS\UserDetail;
|
||||||
use App\Models\OLDLMS\Prescription;
|
use App\Models\OLDLMS\Prescription;
|
||||||
|
use App\Models\OLDLMS\PrescriptionItem;
|
||||||
|
|
||||||
|
use App\Models\Prescription as PrescriptionAso;
|
||||||
|
use App\Models\PrescriptionItem as PrescriptionItemAso;
|
||||||
|
use App\Models\Icd;
|
||||||
|
use App\Models\Organization;
|
||||||
|
use App\Models\Drug;
|
||||||
|
use App\Models\Unit;
|
||||||
|
use Illuminate\Contracts\Support\Renderable;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Modules\Internal\Transformers\LivechatResource;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Illuminate\Routing\Controller;
|
use Illuminate\Routing\Controller;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Dompdf\Dompdf;
|
||||||
|
use Dompdf\Options;
|
||||||
|
use DB;
|
||||||
|
|
||||||
class PrescriptionController extends Controller
|
class PrescriptionController extends Controller
|
||||||
{
|
{
|
||||||
@@ -15,21 +40,31 @@ class PrescriptionController extends Controller
|
|||||||
* @param int|null $id
|
* @param int|null $id
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function index($id = null)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$query = Prescription::query();
|
$startDate = $request->startDate;
|
||||||
if ($id !== null) {
|
$endDate = $request->endDate;
|
||||||
$query->where('nID', $id);
|
|
||||||
|
$livechat = Livechat::with('doctor.user', 'doctor.speciality', 'appointment.appointmentDetail', 'healthCare', 'summary')
|
||||||
|
->where('nTebusObat', '=', 1);
|
||||||
|
// ->where('nIDAppointment', '!=', null)
|
||||||
|
// ->where('nIDAppointment', '!=', '');
|
||||||
|
if ($startDate) {
|
||||||
|
$livechat = $livechat->where('dCreateOn', '>=', $startDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
$prescriptions = $query->select('nID','nIDLiveChat', 'nIDLiveChatSummary', 'nIDDokter', 'sDokterName', 'dTanggalResep', 'sSource', 'nIDUser', 'sKodeResep', 'sDiagnose', 'sStatus')
|
if ($endDate) {
|
||||||
->get();
|
$endDate = date('Y-m-d', strtotime($endDate . ' +1 day'));
|
||||||
|
$livechat = $livechat->where('dCreateOn', '<', $endDate);
|
||||||
|
}
|
||||||
|
|
||||||
// $prescriptions->toArray();
|
$livechat = $livechat->whereHas('summary', function ($query) {
|
||||||
// dd($prescriptions);
|
$query->whereNotNull('nIDLiveChat');
|
||||||
|
});
|
||||||
|
|
||||||
return response()->json($prescriptions);
|
$livechat = $livechat->latest()->paginate(15);
|
||||||
// return response()->json(Helper::paginateResources(LivechatResource::collection($livechat)));
|
|
||||||
|
return response()->json(Helper::paginateResources(LivechatResource::collection($livechat)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -51,6 +86,128 @@ class PrescriptionController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
|
// Insert atau Update ke table prescription di ASO
|
||||||
|
$data = [
|
||||||
|
'livechat_id' => $request->id,
|
||||||
|
'organization_id' => $request->hospital,
|
||||||
|
'icd_code' => $request->diagnosis,
|
||||||
|
];
|
||||||
|
$prescriptionAso = PrescriptionAso::updateOrCreate([
|
||||||
|
'livechat_id' => $request->id
|
||||||
|
], $data);
|
||||||
|
|
||||||
|
// Insert ke table tx_prescription di Linksehat
|
||||||
|
$livechat = Livechat::where('nID', $request->id)->first();
|
||||||
|
$livechatSummary = LivechatSummary::where('nIDLivechat', $request->id)->first();
|
||||||
|
|
||||||
|
$dokterData = Dokter::where('nIDUser', $livechat->nIDDokter)->first();
|
||||||
|
$nIDDokter = $dokterData ? $dokterData->nID : $livechat->nIDDokter;
|
||||||
|
$userDokter = User::where('nID', $livechat->nIDDokter)->first();
|
||||||
|
$userDetailDokter = UserDetail::where('nIDUser', $userDokter->nID)->first();
|
||||||
|
|
||||||
|
$dokter = $userDetailDokter->sTitlePrefix . ' ' . $userDokter->sFirstName . ' ' . $userDokter->sLastName . ' ' . $userDetailDokter->sTitleSuffix;
|
||||||
|
|
||||||
|
$kodeResep = 'LMS' . date('ymd') . rand(1,100);
|
||||||
|
$diagnosis = explode(",",$request->diagnosis);
|
||||||
|
|
||||||
|
if(isset($request->diagnosis) && is_array($diagnosis) && count($diagnosis) > 0) {
|
||||||
|
foreach($diagnosis as $data){
|
||||||
|
$icd = Icd::where('code', $data)->first();
|
||||||
|
array_push($diagnosis, $icd->name);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
$sDiagnosis = implode(", ",$diagnosis);
|
||||||
|
$hospitalData = Organization::where('id', $request->hospital)->first();
|
||||||
|
$hospital = '';
|
||||||
|
if ($hospitalData) {
|
||||||
|
$hospital = $hospitalData->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'nIDLivechat' => $request->id,
|
||||||
|
'nIDLivechatSummary' => $livechatSummary->nID,
|
||||||
|
'nIDDokter' => $nIDDokter,
|
||||||
|
'sDokterName' => $dokter,
|
||||||
|
'dTanggalResep' => date('Y-m-d H:i:s'),
|
||||||
|
'sSource' => 'lms',
|
||||||
|
'nIDUser' => $livechat->nIDUser,
|
||||||
|
'sRegID' => '',
|
||||||
|
'sKodeResep' => $kodeResep,
|
||||||
|
'sDiagnose' => $sDiagnosis,
|
||||||
|
'sKodeRS' => $hospital,
|
||||||
|
];
|
||||||
|
|
||||||
|
$prescription = Prescription::updateOrCreate([
|
||||||
|
'nIDLivechat' => $request->id
|
||||||
|
],$data);
|
||||||
|
|
||||||
|
$medicine = $request->medicine;
|
||||||
|
$customMessages = [
|
||||||
|
'required' => 'Kolom :attribute wajib diisi.',
|
||||||
|
'numeric' => 'Kolom :attribute harus berupa angka.',
|
||||||
|
];
|
||||||
|
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'medicine' => 'required|array',
|
||||||
|
'medicine.*' => 'required',
|
||||||
|
], $customMessages);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return Helper::responseJson([$request->all()],'error', 400, $validator->errors());
|
||||||
|
} else {
|
||||||
|
// BeginTransaction
|
||||||
|
// delete item
|
||||||
|
DB::beginTransaction();
|
||||||
|
PrescriptionItemAso::where('prescription_id', $prescriptionAso->id)->delete();
|
||||||
|
PrescriptionItem::where('nIDPrescription', $prescription->nID)->delete();
|
||||||
|
foreach($medicine as $key => $value){
|
||||||
|
$drugData = Drug::where('id', $value['drug_id'])->first();
|
||||||
|
$drug = '';
|
||||||
|
$drugCode = '';
|
||||||
|
if ($drugData){
|
||||||
|
$drug = $drugData->name;
|
||||||
|
$drugCode = $drugData->code;
|
||||||
|
}
|
||||||
|
$unitData = Unit::where('id', $value['unit_id'])->first();
|
||||||
|
$unit = '';
|
||||||
|
if ($unitData) {
|
||||||
|
$unit = $unitData->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert Data
|
||||||
|
$dataAso = [
|
||||||
|
'prescription_id' => $prescriptionAso->id,
|
||||||
|
'drug_id' => $value['drug_id'],
|
||||||
|
'qty' => $value['qty'],
|
||||||
|
'unit_id' => $value['unit_id'],
|
||||||
|
'signa' => $value['signa'],
|
||||||
|
'note' => $value['note']
|
||||||
|
];
|
||||||
|
$data = [
|
||||||
|
'nIDPrescription' => $prescription->nID,
|
||||||
|
'sItemName' => $drug,
|
||||||
|
'sItemCode' => $drug,
|
||||||
|
'sOriginCode' => $drugCode,
|
||||||
|
'nQty' => $value['qty'],
|
||||||
|
'sSatuan' => $unit,
|
||||||
|
'sSigna' => $value['signa'],
|
||||||
|
'sNote' => $value['note'],
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
// Insert to ASO
|
||||||
|
PrescriptionItemAso::create($dataAso);
|
||||||
|
// Insert to Linksehat
|
||||||
|
PrescriptionItem::create($data);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
DB::rollBack();
|
||||||
|
return Helper::responseJson(status: 'failed', statusCode: 500, message: $th->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DB::commit();
|
||||||
|
return Helper::responseJson(status: 'success', statusCode: 201, message: 'success', data: $request->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Helper::responseJson(status: 'success', statusCode: 200, message: 'Resep Online berhasil ajukan!', data: $prescription);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,4 +250,58 @@ class PrescriptionController extends Controller
|
|||||||
{
|
{
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function downloadPrescription($id){
|
||||||
|
$pdf = new Dompdf();
|
||||||
|
|
||||||
|
$options = new Options();
|
||||||
|
$options->set('isHtml5ParserEnabled', true);
|
||||||
|
$options->set('isPhpEnabled', true);
|
||||||
|
$options->set(['isRemoteEnabled' => true]);
|
||||||
|
$pdf->setOptions($options);
|
||||||
|
|
||||||
|
$pdf->setPaper('A4', 'portrait');
|
||||||
|
|
||||||
|
|
||||||
|
$livechat = Livechat::with('doctor.user', 'doctor.speciality', 'appointment.appointmentDetail', 'healthCare')
|
||||||
|
->where('nIDAppointment', '!=', null)->where('nIDAppointment', '!=', '')
|
||||||
|
->where('nID', $id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
$prescription = Prescription::where('nIDLivechat', $id)->first();
|
||||||
|
$valid_date = date('d-m-Y', strtotime($prescription->dTanggalResep . ' +3 days'));
|
||||||
|
$prescriptionItem = PrescriptionItem::where('nIDPrescription', $prescription->nID)->get();
|
||||||
|
|
||||||
|
$user = User::where('nID', $livechat->nIDUser)->first();
|
||||||
|
$doctor = Dokter::where('nIDUser', $livechat->nIDDokter)->first();
|
||||||
|
|
||||||
|
$patient = [
|
||||||
|
'name' => $user->sFirstName. ' '. $user->sMiddleName. ' '. $user->sLastName,
|
||||||
|
'tgl_lahir' => date('d-m-Y', strtotime($user->dTanggalLahir)),
|
||||||
|
'kelamin' => $user->nIDJenisKelamin == 1 ? 'M' : 'F',
|
||||||
|
'umur' => Helper::calculateAge($user->dTanggalLahir)
|
||||||
|
];
|
||||||
|
|
||||||
|
// Memuat view pdf_view.php ke dalam variabel
|
||||||
|
$data = [
|
||||||
|
'doctor' => $doctor,
|
||||||
|
'items' => $prescriptionItem,
|
||||||
|
'tanggal_resep' => date('d-m-Y', strtotime($prescription->dTanggalResep)),
|
||||||
|
'pasien' => $patient,
|
||||||
|
'valid_date' => $valid_date,
|
||||||
|
];
|
||||||
|
// Halaman 1
|
||||||
|
$html1 = view('pdf.prescription', $data);
|
||||||
|
$htmlCombined = $html1 ;
|
||||||
|
|
||||||
|
$pdf->loadHtml($htmlCombined);
|
||||||
|
$pdf->render();
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
'Content-Type' => 'application/pdf',
|
||||||
|
'Content-Disposition' => 'inline; filename="file.pdf"',
|
||||||
|
];
|
||||||
|
|
||||||
|
return response($pdf->output(), 200, $headers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,6 +215,24 @@ class RequestLogController extends Controller
|
|||||||
return Helper::responseJson(data: $manipulatedIcds);
|
return Helper::responseJson(data: $manipulatedIcds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function hospitals(){
|
||||||
|
$organizations = Organization::query()
|
||||||
|
->where([
|
||||||
|
'type' => 'hospital',
|
||||||
|
'status' => 'active',
|
||||||
|
])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$manipulatedOrganizations = $organizations->map(function ($organization) {
|
||||||
|
// Contoh manipulasi, tambahkan atau ubah properti sesuai kebutuhan
|
||||||
|
return [
|
||||||
|
'value' => $organization->id, // Ganti dengan properti yang sesuai dari model Icd
|
||||||
|
'label' => $organization->name, // Ganti dengan properti yang sesuai dari model Icd
|
||||||
|
];
|
||||||
|
});
|
||||||
|
return Helper::responseJson(data: $manipulatedOrganizations);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the form for editing the specified resource.
|
* Show the form for editing the specified resource.
|
||||||
* @param int $id
|
* @param int $id
|
||||||
@@ -255,6 +273,14 @@ class RequestLogController extends Controller
|
|||||||
$requestLog->catatan = $request->catatan;
|
$requestLog->catatan = $request->catatan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($request->billing_no)) {
|
||||||
|
$requestLog->billing_no = $request->billing_no;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($request->invoice_no)) {
|
||||||
|
$requestLog->invoice_no = $request->invoice_no;
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($request->reason)) {
|
if (!empty($request->reason)) {
|
||||||
$requestLog->reason = $request->reason;
|
$requestLog->reason = $request->reason;
|
||||||
}
|
}
|
||||||
@@ -301,10 +327,12 @@ class RequestLogController extends Controller
|
|||||||
$requestLog = RequestLog::findOrFail($id);
|
$requestLog = RequestLog::findOrFail($id);
|
||||||
$requestLog->status_final_log = null;
|
$requestLog->status_final_log = null;
|
||||||
$requestLog->final_log = 0;
|
$requestLog->final_log = 0;
|
||||||
$requestLog->reason_final = 'Reason Delete ' .$request->reason;
|
$requestLog->reason_final = 'Reason Delete Final LOG' .$request->reason;
|
||||||
$requestLog->save();
|
$requestLog->save();
|
||||||
|
|
||||||
// Hapus semua manfaat log permintaan terkait
|
// Hapus semua manfaat log permintaan terkait
|
||||||
RequestLogBenefit::where('request_log_id', $id)->delete();
|
RequestLogBenefit::where('request_log_id', $id)->delete();
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'error' => false,
|
'error' => false,
|
||||||
'message' => 'Delete Final LOG',
|
'message' => 'Delete Final LOG',
|
||||||
@@ -406,7 +434,13 @@ class RequestLogController extends Controller
|
|||||||
// Update Request LOG untuk lanjut ke Final LOG
|
// Update Request LOG untuk lanjut ke Final LOG
|
||||||
// if (!empty($request->catatan)) {
|
// if (!empty($request->catatan)) {
|
||||||
$requestLog->catatan = $request->catatan;
|
$requestLog->catatan = $request->catatan;
|
||||||
// }
|
}
|
||||||
|
if (!empty($request->billing_no)) {
|
||||||
|
$requestLog->billing_no = $request->billing_no;
|
||||||
|
}
|
||||||
|
if (!empty($request->invoice_no)) {
|
||||||
|
$requestLog->invoice_no = $request->invoice_no;
|
||||||
|
}
|
||||||
if ($request->discharge_date) {
|
if ($request->discharge_date) {
|
||||||
$requestLog->discharge_date = $request->discharge_date;
|
$requestLog->discharge_date = $request->discharge_date;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,6 +238,8 @@ Route::prefix('internal')->group(function () {
|
|||||||
Route::post('claims/{claim_id}/set-final-encounter', [ClaimEncounterController::class, 'setFinalEncounter']);
|
Route::post('claims/{claim_id}/set-final-encounter', [ClaimEncounterController::class, 'setFinalEncounter']);
|
||||||
|
|
||||||
Route::get('claims', [ClaimController::class, 'index']);
|
Route::get('claims', [ClaimController::class, 'index']);
|
||||||
|
Route::get('claims-files-provider', [ClaimController::class, 'filesProvider']);
|
||||||
|
Route::post('download-zip', [ClaimController::class, 'downloadZip']);
|
||||||
Route::get('claims/download-template', [ClaimController::class, 'downloadTemplate']);
|
Route::get('claims/download-template', [ClaimController::class, 'downloadTemplate']);
|
||||||
Route::post('claims/import', [ClaimController::class, 'import']);
|
Route::post('claims/import', [ClaimController::class, 'import']);
|
||||||
Route::post('claims/exportFiled/', [ClaimController::class, 'exportFiled']);
|
Route::post('claims/exportFiled/', [ClaimController::class, 'exportFiled']);
|
||||||
@@ -285,6 +287,10 @@ Route::prefix('internal')->group(function () {
|
|||||||
// search diagnosis
|
// 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']);
|
||||||
|
|
||||||
// insert benefit
|
// insert benefit
|
||||||
Route::post('customer-service/request/insert-benefit', [RequestLogBenefitController::class, 'store']);
|
Route::post('customer-service/request/insert-benefit', [RequestLogBenefitController::class, 'store']);
|
||||||
Route::post('customer-service/request/benefit_data/{id}', [RequestLogBenefitController::class, 'destroy']);
|
Route::post('customer-service/request/benefit_data/{id}', [RequestLogBenefitController::class, 'destroy']);
|
||||||
@@ -301,7 +307,13 @@ Route::prefix('internal')->group(function () {
|
|||||||
Route::resource('appointments', AppointmentController::class);
|
Route::resource('appointments', AppointmentController::class);
|
||||||
Route::get('live-chat/export', [LivechatController::class, 'export']);
|
Route::get('live-chat/export', [LivechatController::class, 'export']);
|
||||||
Route::resource('live-chat', LivechatController::class);
|
Route::resource('live-chat', LivechatController::class);
|
||||||
|
|
||||||
Route::get('prescription', [PrescriptionController::class, 'index']);
|
Route::get('prescription', [PrescriptionController::class, 'index']);
|
||||||
|
|
||||||
|
Route::post('prescription', [PrescriptionController::class, 'store']);
|
||||||
|
Route::get('prescription-download/{id}', [PrescriptionController::class, 'downloadPrescription']);
|
||||||
|
|
||||||
|
|
||||||
Route::get('prescription/{id}', [PrescriptionController::class, 'index']);
|
Route::get('prescription/{id}', [PrescriptionController::class, 'index']);
|
||||||
Route::get('doctorrating', [DoctorRatingController::class, 'index']);
|
Route::get('doctorrating', [DoctorRatingController::class, 'index']);
|
||||||
Route::get('doctorrating/{id}', [PrescriptionController::class, 'index']);
|
Route::get('doctorrating/{id}', [PrescriptionController::class, 'index']);
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ class DoctorResource extends JsonResource
|
|||||||
'speciality_id' => $item->speciality->id,
|
'speciality_id' => $item->speciality->id,
|
||||||
];
|
];
|
||||||
}),
|
}),
|
||||||
|
'period_start' => $items->pluck('period_start')->first(),
|
||||||
|
'period_end' => $items->pluck('period_end')->first(),
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ namespace Modules\Internal\Transformers;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
|
use App\Models\Prescription;
|
||||||
|
use App\Models\PrescriptionItem;
|
||||||
|
|
||||||
class LivechatResource extends JsonResource
|
class LivechatResource extends JsonResource
|
||||||
{
|
{
|
||||||
@@ -16,6 +18,20 @@ class LivechatResource extends JsonResource
|
|||||||
*/
|
*/
|
||||||
public function toArray($request)
|
public function toArray($request)
|
||||||
{
|
{
|
||||||
|
$prescription = Prescription::where('livechat_id', $this->nID)->first();
|
||||||
|
$diagnosis = $prescription ? $prescription->icd_code : '';
|
||||||
|
$hospital = $prescription ? $prescription->organization_id : '';
|
||||||
|
|
||||||
|
$prescriptionItem = $prescription ? PrescriptionItem::where('prescription_id', $prescription->id)->get() : [
|
||||||
|
[
|
||||||
|
'drug_id' => 0,
|
||||||
|
'qty' => 0,
|
||||||
|
'signa' => '',
|
||||||
|
'unit_id' => 0,
|
||||||
|
'note' => '', // input to database
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
$livechat = [
|
$livechat = [
|
||||||
'id' => $this->nID,
|
'id' => $this->nID,
|
||||||
'doctor_name' => isset($this->doctor->user->sFirstName) ? $this->doctor->user->detail->sTitlePrefix . '. ' . $this->doctor->user->sFirstName . ' ' . $this->doctor->user->sLastName . ' ' . $this->doctor->user->detail->sTitleSuffix : null,
|
'doctor_name' => isset($this->doctor->user->sFirstName) ? $this->doctor->user->detail->sTitlePrefix . '. ' . $this->doctor->user->sFirstName . ' ' . $this->doctor->user->sLastName . ' ' . $this->doctor->user->detail->sTitleSuffix : null,
|
||||||
@@ -36,6 +52,9 @@ class LivechatResource extends JsonResource
|
|||||||
'appointment_media' => $this->appointment->sMedia ?? null,
|
'appointment_media' => $this->appointment->sMedia ?? null,
|
||||||
'status_chat' => $this->status_name ?? null,
|
'status_chat' => $this->status_name ?? null,
|
||||||
'payment_method' => $this->appointment->payment_method ?? null,
|
'payment_method' => $this->appointment->payment_method ?? null,
|
||||||
|
'diagnosis' => $diagnosis,
|
||||||
|
'hospital' => $hospital,
|
||||||
|
'medicine' => $prescriptionItem
|
||||||
];
|
];
|
||||||
|
|
||||||
$start_time = $this->dStartTime;
|
$start_time = $this->dStartTime;
|
||||||
|
|||||||
@@ -113,6 +113,9 @@ class RequestLogShowResource extends JsonResource
|
|||||||
$data = [
|
$data = [
|
||||||
'id' => $requestLog['id'],
|
'id' => $requestLog['id'],
|
||||||
'code' => $requestLog['code'],
|
'code' => $requestLog['code'],
|
||||||
|
'invoice_no' => $requestLog['invoice_no'],
|
||||||
|
'billing_no' => $requestLog['billing_no'],
|
||||||
|
'code' => $requestLog['code'],
|
||||||
'code_claim' => $claimCode,
|
'code_claim' => $claimCode,
|
||||||
'member_id' => $requestLog['member']['member_id'],
|
'member_id' => $requestLog['member']['member_id'],
|
||||||
'corporate_id' => $corporateId,
|
'corporate_id' => $corporateId,
|
||||||
|
|||||||
21
Modules/Linksehat/Helpers/Doctor/ApiResponse.php
Normal file
21
Modules/Linksehat/Helpers/Doctor/ApiResponse.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Linksehat\Helpers\Doctor;
|
||||||
|
|
||||||
|
class ApiResponse
|
||||||
|
{
|
||||||
|
public static function apiResponse(string $status, array|object $data = null, string|array|object $message = null, int $statusCode)
|
||||||
|
{
|
||||||
|
if ($message instanceof \Illuminate\Support\MessageBag) {
|
||||||
|
$message = $message->first();
|
||||||
|
}
|
||||||
|
return response()->json([
|
||||||
|
'meta' => [
|
||||||
|
'status' => $status,
|
||||||
|
'code' => $statusCode,
|
||||||
|
'message' => $message
|
||||||
|
],
|
||||||
|
'data' => $data,
|
||||||
|
], $statusCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,9 @@
|
|||||||
namespace Modules\Linksehat\Http\Controllers\Api;
|
namespace Modules\Linksehat\Http\Controllers\Api;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\OLDLMS\User;
|
use App\Models\OLDLMS\User;
|
||||||
|
use App\Models\Icd;
|
||||||
|
use App\Models\Drug;
|
||||||
|
use App\Models\Unit;
|
||||||
use Illuminate\Contracts\Support\Renderable;
|
use Illuminate\Contracts\Support\Renderable;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Routing\Controller;
|
use Illuminate\Routing\Controller;
|
||||||
@@ -93,5 +96,51 @@ class AutocompleteController extends Controller {
|
|||||||
}
|
}
|
||||||
return Helper::responseJson($data);
|
return Helper::responseJson($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function diagnosis(){
|
||||||
|
$icds = Icd::query()
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$manipulatedIcds = $icds->map(function ($icd) {
|
||||||
|
// Contoh manipulasi, tambahkan atau ubah properti sesuai kebutuhan
|
||||||
|
return [
|
||||||
|
'value' => $icd->code, // Ganti dengan properti yang sesuai dari model Icd
|
||||||
|
'label' => $icd->code . ' - ' .$icd->name, // Ganti dengan properti yang sesuai dari model Icd
|
||||||
|
];
|
||||||
|
});
|
||||||
|
return Helper::responseJson(data: $manipulatedIcds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function drugList(Request $request){
|
||||||
|
$drugs = Drug::query()
|
||||||
|
->where([
|
||||||
|
'atc_code' => 'lms', // ini untuk menggunakan list obat yang baru
|
||||||
|
])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$manipulatedDrugs = $drugs->map(function ($drug) {
|
||||||
|
// Contoh manipulasi, tambahkan atau ubah properti sesuai kebutuhan
|
||||||
|
return [
|
||||||
|
'value' => $drug->id, // Ganti dengan properti yang sesuai dari model Icd
|
||||||
|
'label' => $drug->name, // Ganti dengan properti yang sesuai dari model Icd
|
||||||
|
];
|
||||||
|
});
|
||||||
|
return Helper::responseJson(data: $manipulatedDrugs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unitList(Request $request){
|
||||||
|
$units = Unit::query()
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$manipulatedUnits = $units->map(function ($unit) {
|
||||||
|
// Contoh manipulasi, tambahkan atau ubah properti sesuai kebutuhan
|
||||||
|
return [
|
||||||
|
'value' => $unit->id, // Ganti dengan properti yang sesuai dari model Icd
|
||||||
|
'label' => $unit->name, // Ganti dengan properti yang sesuai dari model Icd
|
||||||
|
];
|
||||||
|
});
|
||||||
|
return Helper::responseJson(data: $manipulatedUnits);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
323
Modules/Linksehat/Http/Controllers/Api/ChatController.php
Normal file
323
Modules/Linksehat/Http/Controllers/Api/ChatController.php
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Linksehat\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use App\Models\Channel;
|
||||||
|
use App\Events\ChatMessageSent;
|
||||||
|
use App\Models\UserChannel;
|
||||||
|
use App\Models\Message;
|
||||||
|
use App\Models\File;
|
||||||
|
use App\Models\Livechat;
|
||||||
|
use App\Models\Person;
|
||||||
|
use App\Models\OLDLMS\User;
|
||||||
|
use App\Models\OLDLMS\UserDetail;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Routing\Controller;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Dompdf\Dompdf;
|
||||||
|
use Dompdf\Options;
|
||||||
|
use Pusher\Pusher;
|
||||||
|
|
||||||
|
class ChatController extends Controller
|
||||||
|
{
|
||||||
|
public function createChannel(Request $request){
|
||||||
|
// Validasi data yang diterima dari request
|
||||||
|
$validatedData = $request->validate([
|
||||||
|
'member_id' => 'required',
|
||||||
|
'doctor_id' => 'required',
|
||||||
|
], [
|
||||||
|
'member_id.required' => 'Member ID harus diisi.',
|
||||||
|
'doctor_id.required' => 'Doctor ID harus diisi.',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Buat dan simpan data channel ke dalam tabel
|
||||||
|
$channel = Channel::updateOrCreate([
|
||||||
|
'name' => $request->member_id .'_' . $request->doctor_id,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => $request->member_id .'_' . $request->doctor_id,
|
||||||
|
'type' => $request->type,
|
||||||
|
'member_id' => $request->member_id,
|
||||||
|
'doctor_id' => $request->doctor_id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Menggunakan updateOrCreate untuk menambahkan data UserChannel untuk member_id
|
||||||
|
$userChannelMember = UserChannel::updateOrCreate(
|
||||||
|
[
|
||||||
|
'user_id' => $request->member_id,
|
||||||
|
'channel_id' => $channel->id
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'user_id' => $request->member_id,
|
||||||
|
'channel_id' => $channel->id
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Menggunakan updateOrCreate untuk menambahkan data UserChannel untuk doctor_id
|
||||||
|
$userChannelDoctor = UserChannel::updateOrCreate(
|
||||||
|
[
|
||||||
|
'user_id' => $request->doctor_id,
|
||||||
|
'channel_id' => $channel->id
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'user_id' => $request->doctor_id,
|
||||||
|
'channel_id' => $channel->id
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Berikan respons yang sesuai ke klien
|
||||||
|
return response()->json(['message' => 'Channel created successfully', 'channel' => $channel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listChannel(Request $request){
|
||||||
|
// Validasi request jika diperlukan
|
||||||
|
$channel = Channel::where('member_id',$request->user_id)->get()->toArray();
|
||||||
|
|
||||||
|
if (!$channel) {
|
||||||
|
$dataChannel = Channel::where('doctor_id',$request->user_id)->get()->toArray();
|
||||||
|
$data = [];
|
||||||
|
if ($dataChannel){
|
||||||
|
foreach($dataChannel as $d){
|
||||||
|
$user = User::with('detail')->where('nID', $d['member_id'])->first();
|
||||||
|
$lastMessage = Message::where('channel_id', $d['id'])
|
||||||
|
->latest('created_at')
|
||||||
|
->first();
|
||||||
|
$urlAvatarDefault = $user->detail->nIDJenisKelamin == 1 ? 'https://linksehat.dev/assets/img/users/male-avatar.png' : 'https://linksehat.dev/assets/img/users/female-avatar.png';
|
||||||
|
$avatarMember = $user->detail->sImage ?? $urlAvatarDefault;
|
||||||
|
|
||||||
|
$arr['id'] = $d['id'];
|
||||||
|
$arr['avatar'] = $avatarMember;
|
||||||
|
$arr['name'] = $user->sFirstName .' '.$user->sLastName;
|
||||||
|
$arr['last_message'] = $lastMessage;
|
||||||
|
|
||||||
|
array_push($data, $arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$channel = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Get List Channel successfully', 'channel' => $channel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendMessage(Request $request)
|
||||||
|
{
|
||||||
|
// Validasi request jika diperlukan
|
||||||
|
$validatedData = $request->validate([
|
||||||
|
'user_id' => 'required'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Ambil data dari request
|
||||||
|
$message = Message::create([
|
||||||
|
'content' => $request->message,
|
||||||
|
'from_user' => $request->user_id,
|
||||||
|
'channel_id' => $request->channel_id,
|
||||||
|
'type' => $request->message ? 'text' : 'file'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$pathFile = null;
|
||||||
|
if ($request->hasFile('file_chat')) {
|
||||||
|
foreach ($request->file_chat as $file) {
|
||||||
|
$pathFile = File::storeFile('chat', $message->id, $file);
|
||||||
|
File::updateOrCreate([
|
||||||
|
'fileable_type'=>'App\Models\Message',
|
||||||
|
'fileable_id' => $message->id,
|
||||||
|
'type' => 'chat',
|
||||||
|
'name' => File::getFileName('chat', $message->id, $file),
|
||||||
|
'original_name' => $file->getClientOriginalName(),
|
||||||
|
'extension' => $file->getClientOriginalExtension(),
|
||||||
|
'path' => $pathFile,
|
||||||
|
'created_by' => auth()->user()->id,
|
||||||
|
'updated_by' => auth()->user()->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$message->update([
|
||||||
|
'content' => env('LMS_APP_STORAGE') . 'storage/' . $pathFile,
|
||||||
|
'from_user' => $request->user_id,
|
||||||
|
'channel_id' => $request->channel_id,
|
||||||
|
'type' => 'file',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
// Berikan respons yang sesuai ke klien
|
||||||
|
|
||||||
|
$channel = Channel::where('id',$request->channel_id)->first();
|
||||||
|
if($channel->member_id == $request->user_id){
|
||||||
|
// Get nama dokter
|
||||||
|
$person = Person::where('id', $channel->doctor_id)->first();
|
||||||
|
$name = $person->name;
|
||||||
|
} else {
|
||||||
|
// Get nama pasien
|
||||||
|
$person = User::where('nID', $channel->member_id)->first();
|
||||||
|
$name = $person->sFirstName . ' ' . $person->sLastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatMessageSent::dispatch($message);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Message sent successfully',
|
||||||
|
'data' => [
|
||||||
|
'header' => $name,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMessage(Request $request)
|
||||||
|
{
|
||||||
|
// Buat instance Pusher dengan konfigurasi yang sesuai
|
||||||
|
$channel = Channel::where('id',$request->channel_id)->first();
|
||||||
|
$livechat = Livechat::where([
|
||||||
|
'doctor_id' => $channel->doctor_id,
|
||||||
|
'patient_id' => $channel->member_id,
|
||||||
|
])->latest('created_at')->first();
|
||||||
|
|
||||||
|
if($channel->member_id == $request->user_id){
|
||||||
|
// Get nama dokter
|
||||||
|
$person = Person::where('id', $channel->doctor_id)->first();
|
||||||
|
$name = $person->name;
|
||||||
|
$avatar = '';
|
||||||
|
$age = '';
|
||||||
|
$gender = '';
|
||||||
|
$question = '';
|
||||||
|
|
||||||
|
$consultationStart = $livechat->start_date;
|
||||||
|
$consultationEnd = $livechat->end_date;
|
||||||
|
$work = '';
|
||||||
|
$address = '';
|
||||||
|
} else {
|
||||||
|
// Get nama pasien
|
||||||
|
$user = User::where('nID', $channel->member_id)->with('detail')->first();
|
||||||
|
$name = $user->sFirstName . ' ' . $user->sLastName;
|
||||||
|
$urlAvatarDefault = $user->detail->nIDJenisKelamin == 1 ? 'https://linksehat.dev/assets/img/users/male-avatar.png' : 'https://linksehat.dev/assets/img/users/female-avatar.png';
|
||||||
|
$avatar = $user->detail->sImage ?? $urlAvatarDefault;
|
||||||
|
$gender = DB::connection('oldlms')->table('tm_jenis_kelamin')->where('nID', $user->detail->nIDJenisKelamin)->first('sJenisKelamin');
|
||||||
|
if ($gender){
|
||||||
|
$gender = $gender->sJenisKelamin;
|
||||||
|
}
|
||||||
|
$age = Helper::calculateAge($user->detail->dTanggalLahir);
|
||||||
|
$question = $livechat->descriptions;
|
||||||
|
$consultationStart = $livechat->start_date;
|
||||||
|
$consultationEnd = $livechat->end_date;
|
||||||
|
$work = DB::connection('oldlms')->table('tm_pekerjaan')->where('nID', $user->detail->nIDPekerjaan)->first('sPekerjaan');
|
||||||
|
|
||||||
|
if($work){
|
||||||
|
$work = $work->sPekerjaan;
|
||||||
|
}
|
||||||
|
$address = DB::connection('oldlms')->table('tm_users_address')->where('nIDUser', $user->nID)->first('sAlamat');
|
||||||
|
if($address){
|
||||||
|
$address = $address->sAlamat;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ini Untul Chat
|
||||||
|
$perPage = $request->input('per_page', 10); // Default 10 pesan per halaman
|
||||||
|
$page = $request->input('page', 1); // Default halaman 1
|
||||||
|
|
||||||
|
$data = Message::where('channel_id', $request->channel_id)
|
||||||
|
->where('type', '!=', 'trigger')
|
||||||
|
->orderBy('created_at', 'desc') // Urutkan berdasarkan created_at secara descending
|
||||||
|
->paginate($perPage, ['*'], 'page', $page);
|
||||||
|
|
||||||
|
// Data Consultation Summary
|
||||||
|
$consultationSummary = [
|
||||||
|
'subject' => $livechat->subject,
|
||||||
|
'object' => $livechat->object,
|
||||||
|
'assessment' => $livechat->assessment,
|
||||||
|
'plan' => $livechat->plan,
|
||||||
|
];
|
||||||
|
|
||||||
|
$healthSertificate = false;
|
||||||
|
if ($livechat->health_certificate_start && $livechat->health_certificate_end){
|
||||||
|
$healthSertificate = True;
|
||||||
|
}
|
||||||
|
// Berikan respons yang sesuai ke klien
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Message sent successfully',
|
||||||
|
'data' => [
|
||||||
|
'header' => $name,
|
||||||
|
'avatar' => $avatar,
|
||||||
|
'gender' => $gender,
|
||||||
|
'age' => $age,
|
||||||
|
'question' => $question,
|
||||||
|
'start' => $consultationStart,
|
||||||
|
'end' => $consultationEnd,
|
||||||
|
'work' => $work,
|
||||||
|
'address' => $address,
|
||||||
|
'chat' => $data->items(),
|
||||||
|
'pagination' => [
|
||||||
|
'total' => $data->total(),
|
||||||
|
'per_page' => $data->perPage(),
|
||||||
|
'current_page' => $data->currentPage(),
|
||||||
|
'last_page' => $data->lastPage(),
|
||||||
|
'from' => $data->firstItem(),
|
||||||
|
'to' => $data->lastItem(),
|
||||||
|
],
|
||||||
|
'summary' => $consultationSummary,
|
||||||
|
'livechat_id' => $livechat->id,
|
||||||
|
'health_sertificate' => $healthSertificate,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadHealtcare($id){
|
||||||
|
$pdf = new Dompdf();
|
||||||
|
|
||||||
|
$options = new Options();
|
||||||
|
$options->set('isHtml5ParserEnabled', true);
|
||||||
|
$options->set('isPhpEnabled', true);
|
||||||
|
$options->set(['isRemoteEnabled' => true]);
|
||||||
|
$pdf->setOptions($options);
|
||||||
|
|
||||||
|
$pdf->setPaper('A4', 'portrait');
|
||||||
|
|
||||||
|
$livechat = Livechat::where([
|
||||||
|
'id' => $id
|
||||||
|
])->latest('created_at')->first();
|
||||||
|
|
||||||
|
$user = User::where('nID', $livechat->patient_id)->with('detail')->first();
|
||||||
|
$name = $user->sFirstName . ' ' . $user->sLastName;
|
||||||
|
$age = Helper::calculateAge($user->detail->dTanggalLahir);
|
||||||
|
|
||||||
|
$person = Person::where('id', $livechat->doctor_id)->first();
|
||||||
|
$doctorName = $person->name;
|
||||||
|
|
||||||
|
$work = DB::connection('oldlms')->table('tm_pekerjaan')->where('nID', $user->detail->nIDPekerjaan)->first('sPekerjaan');
|
||||||
|
if($work){
|
||||||
|
$work = $work->sPekerjaan;
|
||||||
|
}
|
||||||
|
$address = DB::connection('oldlms')->table('tm_users_address')->where('nIDUser', $user->nID)->first('sAlamat');
|
||||||
|
if($address){
|
||||||
|
$address = $address->sAlamat;
|
||||||
|
}
|
||||||
|
// Memuat view pdf_view.php ke dalam variabel
|
||||||
|
$calculateDate = Helper::calculateDateDifference($livechat->health_certificate_start, $livechat->health_certificate_end);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name' => $name,
|
||||||
|
'age' => $age,
|
||||||
|
'work' => $work,
|
||||||
|
'address' => $address,
|
||||||
|
'doctor_name' => $doctorName,
|
||||||
|
'date' => $livechat->created_at,
|
||||||
|
'start_date' => $livechat->health_certificate_start,
|
||||||
|
'end_date' => $livechat->health_certificate_end,
|
||||||
|
'calculate_date' => $calculateDate
|
||||||
|
];
|
||||||
|
// Halaman 1
|
||||||
|
$html1 = view('pdf.health_sertificate', $data);
|
||||||
|
$htmlCombined = $html1 ;
|
||||||
|
|
||||||
|
$pdf->loadHtml($htmlCombined);
|
||||||
|
$pdf->render();
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
'Content-Type' => 'application/pdf',
|
||||||
|
'Content-Disposition' => 'inline; filename="file.pdf"',
|
||||||
|
];
|
||||||
|
|
||||||
|
return response($pdf->output(), 200, $headers);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Linksehat\Http\Controllers\Api\Doctor;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use Crypt;
|
||||||
|
use Error;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use Modules\Internal\Emails\SendVerifyEmail;
|
||||||
|
use Modules\Internal\Events\ForgetPassword;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Modules\HospitalPortal\Helpers\ApiResponse;
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use Illuminate\Support\Facades\View;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class AuthDoctorController extends Controller
|
||||||
|
{
|
||||||
|
public function login(Request $request)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'email' => $request->email,
|
||||||
|
'password' => $request->password
|
||||||
|
];
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'email' => 'required|email',
|
||||||
|
'password' => 'required'
|
||||||
|
], [
|
||||||
|
'email.required' => trans('Validation.required',['attribute' => 'Email']),
|
||||||
|
'email.email' => trans('Validation.email'),
|
||||||
|
'password.required' => trans('Validation.required',['attribute' => 'Password']),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails())
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$user = User::where('email', $request->email)->first();
|
||||||
|
if (!$user) {
|
||||||
|
return ApiResponse::apiResponse('Not Found', $data, trans('Message.not_found'), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Hash::check($request->password, $user->password)) {
|
||||||
|
return ApiResponse::apiResponse('Bad Request', $data, trans('Message.password'), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$res_data = [
|
||||||
|
// 'user' => $user,
|
||||||
|
'token' => $user->createToken('app')->plainTextToken
|
||||||
|
];
|
||||||
|
|
||||||
|
return ApiResponse::apiResponse("Success", $res_data, trans('Message.success'), 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logout(Request $request)
|
||||||
|
{
|
||||||
|
$request->user()->tokens()->delete();
|
||||||
|
|
||||||
|
return ApiResponse::apiResponse('Success', [], trans('Message.logout'), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function forgotPassword(Request $request)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'email' => $request->email,
|
||||||
|
];
|
||||||
|
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'email' => 'required|email',
|
||||||
|
], [
|
||||||
|
'email.required' => trans('Validation.required',['attribute' => 'Email']),
|
||||||
|
'email.email' => trans('Validation.email'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails())
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$user = User::where('email', $request->email)->first();
|
||||||
|
if (!$user) {
|
||||||
|
return ApiResponse::apiResponse('Not Found', $data, trans('Message.not_found'), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
//send email
|
||||||
|
// Insert data notifications
|
||||||
|
$emailTo = $request->email;
|
||||||
|
$dataNotif = [
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'email' => $emailTo,
|
||||||
|
'title' => 'Forgot Password',
|
||||||
|
'description' => 'Request forgot password from App Doctor',
|
||||||
|
'type' => 1,
|
||||||
|
'isUnRead' => true,
|
||||||
|
'created_by' => auth()->check() ? auth()->user()->id : null,
|
||||||
|
'created_at' => date('Y-m-d H:i:s'),
|
||||||
|
'updated_at' => date('Y-m-d H:i:s'),
|
||||||
|
];
|
||||||
|
$sendNotif = Helper::insertNotification($dataNotif);
|
||||||
|
//Insert data password reset
|
||||||
|
$token = mt_rand(100000, 999999); // Menghasilkan angka acak antara 100000 dan 999999
|
||||||
|
$p_resets = DB::table('password_resets')
|
||||||
|
->insert([
|
||||||
|
'email' => $request->email,
|
||||||
|
'token' => $token,
|
||||||
|
'created_at' => date('Y-m-d H:i:s'),
|
||||||
|
]);
|
||||||
|
// Send Email after insert notifications
|
||||||
|
if($sendNotif && $p_resets)
|
||||||
|
{
|
||||||
|
//send to alarm
|
||||||
|
$nameTo = 'User';
|
||||||
|
$dataEmail = [
|
||||||
|
'email' => $emailTo,
|
||||||
|
'name' => $nameTo,
|
||||||
|
'subject' => 'Request Forgot Password from App Doctor Date '. date('Y-m-d H:i:s'),
|
||||||
|
'body' => View::make('email/forgot_password', ['token' => $token])->render(),
|
||||||
|
];
|
||||||
|
Helper::sendEmail($dataEmail);
|
||||||
|
|
||||||
|
$res = DB::table('password_resets')
|
||||||
|
->where('email', '=', $request->email)
|
||||||
|
->where('token', '=', $token)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return ApiResponse::apiResponse("Success", $res, trans('Message.success'), 200);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse("Internal Server Error", $data, trans('Message.server_error'), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verifCode(Request $request)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'email' => $request->email,
|
||||||
|
'token' => $request->token,
|
||||||
|
];
|
||||||
|
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'email' => 'required|email',
|
||||||
|
'token' => 'required|numeric',
|
||||||
|
], [
|
||||||
|
'email.required' => trans('Validation.required',['attribute' => 'Email']),
|
||||||
|
'email.email' => trans('Validation.email'),
|
||||||
|
'token.required' => trans('Validation.required',['attribute' => 'Token']),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails())
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Check Time
|
||||||
|
$check = DB::table('password_resets')
|
||||||
|
->where('email', '=', $request->email)
|
||||||
|
->where('token', '=', $request->token)
|
||||||
|
->select('created_at')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if($check)
|
||||||
|
{
|
||||||
|
$created_at = strtotime($check->created_at); // Konversi string waktu ke UNIX timestamp
|
||||||
|
$now = time(); // Waktu sekarang dalam UNIX timestamp
|
||||||
|
|
||||||
|
// Hitung selisih waktu dalam menit
|
||||||
|
$diffInMinutes = ($now - $created_at) / 60;
|
||||||
|
|
||||||
|
if ($diffInMinutes > 60) {
|
||||||
|
return ApiResponse::apiResponse('Not Found', $data, trans('Message.token_expired'), 404);
|
||||||
|
} else {
|
||||||
|
// Lanjutkan dengan proses pemulihan kata sandi
|
||||||
|
return ApiResponse::apiResponse("Success", $data, trans('Message.success'), 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Not Found', $data, trans('Message.not_found'), 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resetPassword(Request $request)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'email' => $request->email,
|
||||||
|
'token' => $request->token,
|
||||||
|
'new_password' => $request->new_password
|
||||||
|
];
|
||||||
|
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'email' => 'required|email',
|
||||||
|
'token' => 'required|numeric',
|
||||||
|
'new_password' => [
|
||||||
|
'required',
|
||||||
|
'min:8',
|
||||||
|
'regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/'
|
||||||
|
]
|
||||||
|
], [
|
||||||
|
'email.required' => trans('Validation.required',['attribute' => 'Email']),
|
||||||
|
'email.email' => trans('Validation.email'),
|
||||||
|
'token.required' => trans('Validation.required',['attribute' => 'Token']),
|
||||||
|
'new_password.required' => trans('Validation.required',['attribute' => 'New Password']),
|
||||||
|
'new_password.min' => trans('Validation.min',['attribute' => 'New Password']),
|
||||||
|
'new_password.regex' => trans('Validation.regex',['attribute' => 'New Password']),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails())
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Check Time
|
||||||
|
$check = DB::table('password_resets')
|
||||||
|
->where('email', '=', $request->email)
|
||||||
|
->where('token', '=', $request->token)
|
||||||
|
->select('created_at')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if($check)
|
||||||
|
{
|
||||||
|
$created_at = strtotime($check->created_at); // Konversi string waktu ke UNIX timestamp
|
||||||
|
$now = time(); // Waktu sekarang dalam UNIX timestamp
|
||||||
|
|
||||||
|
// Hitung selisih waktu dalam menit
|
||||||
|
$diffInMinutes = ($now - $created_at) / 60;
|
||||||
|
|
||||||
|
if ($diffInMinutes > 60) {
|
||||||
|
return ApiResponse::apiResponse('Not Found', $data, trans('Message.token_expired'), 404);
|
||||||
|
} else {
|
||||||
|
// Lanjutkan dengan proses pemulihan kata sandi
|
||||||
|
$user = User::where('email', $request->email)->first();
|
||||||
|
if ($user)
|
||||||
|
{
|
||||||
|
$newPassword = Hash::make($request->new_password);
|
||||||
|
$user->password = $newPassword;
|
||||||
|
$user->save();
|
||||||
|
return ApiResponse::apiResponse("Success", $data, trans('Message.success'), 200);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Not Found', $data, trans('Message.token_expired'), 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Not Found', $data, trans('Message.not_found'), 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Linksehat\Http\Controllers\Api\Doctor;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\OLDLMS\User as UserLMS;
|
||||||
|
use App\Models\Livechat;
|
||||||
|
use App\Models\Channel;
|
||||||
|
use App\Models\Message;
|
||||||
|
use App\Models\Prescription;
|
||||||
|
use App\Models\PrescriptionItem;
|
||||||
|
use Crypt;
|
||||||
|
use Error;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use Modules\Internal\Emails\SendVerifyEmail;
|
||||||
|
use Modules\Internal\Events\ForgetPassword;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Modules\HospitalPortal\Helpers\ApiResponse;
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use Illuminate\Support\Facades\View;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class ChatDoctorController extends Controller
|
||||||
|
{
|
||||||
|
public function getChat()
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'user_id' => auth()->check() ? auth()->user()->id : null,
|
||||||
|
];
|
||||||
|
$user_id = auth()->check() ? auth()->user()->id : null;
|
||||||
|
//Get data Chat
|
||||||
|
$user = User::where('id',$user_id)->with('person')->first();
|
||||||
|
$chat = Livechat::where([
|
||||||
|
'doctor_id'=> $user->person_id,
|
||||||
|
'accept_date'=> null,
|
||||||
|
'status' => 1
|
||||||
|
])->get();
|
||||||
|
|
||||||
|
$dataIncomingChat = [];
|
||||||
|
if($chat) {
|
||||||
|
foreach($chat as $c){
|
||||||
|
$patient = UserLMS::where('nID',$c->patient_id)->with('detail')->first();
|
||||||
|
$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;
|
||||||
|
$arr['id'] = $c->id;
|
||||||
|
$arr['patient_id'] = $patient->nID;
|
||||||
|
$arr['avatar'] = $avatarMember;
|
||||||
|
$arr['name'] = $patient->sFirstName .' '.$patient->sLastName; ;
|
||||||
|
array_push($dataIncomingChat, $arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$dataChannel = Channel::where('doctor_id',$user->person_id)->get()->toArray();
|
||||||
|
$dataOnGoing = [];
|
||||||
|
if ($dataChannel){
|
||||||
|
foreach($dataChannel as $d){
|
||||||
|
$user = UserLMS::with('detail')->where('nID', $d['member_id'])->first();
|
||||||
|
$lastMessage = Message::where('channel_id', $d['id'])
|
||||||
|
->latest('created_at')
|
||||||
|
->first();
|
||||||
|
if ($user->detail){
|
||||||
|
$urlAvatarDefault = $user->detail->nIDJenisKelamin == 1 ? 'https://linksehat.dev/assets/img/users/male-avatar.png' : 'https://linksehat.dev/assets/img/users/female-avatar.png';
|
||||||
|
$avatarMember = $user->detail->sImage ?? $urlAvatarDefault;
|
||||||
|
} else {
|
||||||
|
$avatarMember = 'https://linksehat.dev/assets/img/users/male-avatar.png';
|
||||||
|
}
|
||||||
|
|
||||||
|
$arr['id'] = $d['id'];
|
||||||
|
$arr['avatar'] = $avatarMember;
|
||||||
|
$arr['name'] = $user->sFirstName .' '.$user->sLastName;
|
||||||
|
$arr['last_message'] = $lastMessage;
|
||||||
|
|
||||||
|
array_push($dataOnGoing, $arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$channel = $data;
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'incoming_chat' => $dataIncomingChat,
|
||||||
|
'ongoing_chat' => $dataOnGoing
|
||||||
|
];
|
||||||
|
|
||||||
|
return ApiResponse::apiResponse("Success", $data, trans('Message.success'), 200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getChatDetail($id){
|
||||||
|
$livechat = Livechat::find($id);
|
||||||
|
$user = UserLMS::with('detail')->where('nID', $livechat->patient_id)->first();
|
||||||
|
$urlAvatarDefault = $user->detail->nIDJenisKelamin == 1 ? 'https://linksehat.dev/assets/img/users/male-avatar.png' : 'https://linksehat.dev/assets/img/users/female-avatar.png';
|
||||||
|
$avatarMember = $user->detail->sImage ?? $urlAvatarDefault;
|
||||||
|
$gender = DB::connection('oldlms')->table('tm_jenis_kelamin')->where('nID', $user->detail->nIDJenisKelamin)->first('sJenisKelamin');
|
||||||
|
$maritalStaus = DB::connection('oldlms')->table('tm_status_pernikahan')->where('nID', $user->detail->sMartialStatus)->first('sStatusPernikahan');
|
||||||
|
$data = [];
|
||||||
|
if ($livechat->status != 2){
|
||||||
|
$data = [
|
||||||
|
'id' => $user->nID,
|
||||||
|
'name' => $user->sFirstName . ' ' . $user->sLastName,
|
||||||
|
'avatar' => $avatarMember,
|
||||||
|
'gender' => $gender->sJenisKelamin,
|
||||||
|
'marital_status' => $maritalStaus->sStatusPernikahan,
|
||||||
|
'age' => Helper::calculateAge($user->detail->dTanggalLahir),
|
||||||
|
'weight' => $user->detail->sWeight,
|
||||||
|
'height' => $user->detail->sHeight,
|
||||||
|
'question' => $livechat->descriptions,
|
||||||
|
'diseases' => [],
|
||||||
|
'medications' => [],
|
||||||
|
'allergy' => [],
|
||||||
|
'family_history' => []
|
||||||
|
];
|
||||||
|
} else if ($livechat->status == 2){ // sudah accept, tinggal tunggu bayar pasient
|
||||||
|
$data = [
|
||||||
|
'message' => 'waiting payment'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return ApiResponse::apiResponse("Success", $data, trans('Message.success'), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function declineChat(Request $request)
|
||||||
|
{
|
||||||
|
$livechat = Livechat::find($request->id);
|
||||||
|
if ($livechat) {
|
||||||
|
// Memperbarui atribut model
|
||||||
|
$livechat->status = 3; // Decline
|
||||||
|
// Menyimpan perubahan ke database
|
||||||
|
$livechat->save();
|
||||||
|
return ApiResponse::apiResponse("Success",['message' => 'Livechat updated successfully'], trans('Message.success'), 200);
|
||||||
|
} else {
|
||||||
|
return response()->json(['message' => 'Livechat not found'], 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function approveChat(Request $request)
|
||||||
|
{
|
||||||
|
$livechat = Livechat::find($request->id);
|
||||||
|
if ($livechat) {
|
||||||
|
// Memperbarui atribut model
|
||||||
|
$livechat->status = 2; // Accept
|
||||||
|
$livechat->accept_date = date('Y-m-d H:i:s'); // Accept
|
||||||
|
// Menyimpan perubahan ke database
|
||||||
|
$livechat->save();
|
||||||
|
return ApiResponse::apiResponse("Success",['message' => 'Livechat updated successfully'], trans('Message.success'), 200);
|
||||||
|
} else {
|
||||||
|
return response()->json(['message' => 'Livechat not found'], 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function endChat(Request $request)
|
||||||
|
{
|
||||||
|
$livechat = Livechat::find($request->id);
|
||||||
|
if ($livechat) {
|
||||||
|
// Memperbarui atribut model
|
||||||
|
$livechat->status = 6; // End Chat
|
||||||
|
$livechat->end_date = date('Y-m-d H:i:s'); // Accept
|
||||||
|
// Menyimpan perubahan ke database
|
||||||
|
$livechat->save();
|
||||||
|
return ApiResponse::apiResponse("Success",['message' => 'Livechat updated successfully'], trans('Message.success'), 200);
|
||||||
|
} else {
|
||||||
|
return response()->json(['message' => 'Livechat not found'], 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function summaryChat(Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$livechat = Livechat::find($request->id);
|
||||||
|
if ($livechat) {
|
||||||
|
// Memperbarui atribut model
|
||||||
|
$livechat->subject = $request->subject; // Subject
|
||||||
|
$livechat->object = $request->object; // Object
|
||||||
|
$livechat->assessment = $request->assessment; // Assessment
|
||||||
|
$livechat->plan = $request->plan; // Plan
|
||||||
|
|
||||||
|
$livechat->health_certificate_start = $request->health_certificate_start; // start
|
||||||
|
$livechat->health_certificate_end = $request->health_certificate_end; // end
|
||||||
|
// Menyimpan perubahan ke database
|
||||||
|
$livechat->save();
|
||||||
|
|
||||||
|
$prescriptions = Prescription::create([
|
||||||
|
'livechat_id' => $livechat->id,
|
||||||
|
'organization_id' => $livechat->organization_id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($request->prescriptions) {
|
||||||
|
foreach ($request->prescriptions as $prescription) {
|
||||||
|
$prescriptionItem = PrescriptionItem::create([
|
||||||
|
'prescription_id' => $prescriptions->id,
|
||||||
|
'drug_id' => $prescription['medicine'],
|
||||||
|
'signa' => $prescription['dosis'],
|
||||||
|
'direction' => $prescription['direction'],
|
||||||
|
'note' => $prescription['note'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ApiResponse::apiResponse("Success",['message' => 'Livechat updated successfully'], trans('Message.success'), 200);
|
||||||
|
} else {
|
||||||
|
return response()->json(['message' => 'Livechat not found'], 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Linksehat\Http\Controllers\Api\Doctor;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use Crypt;
|
||||||
|
use Error;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use Modules\Internal\Emails\SendVerifyEmail;
|
||||||
|
use Modules\Internal\Events\ForgetPassword;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Modules\HospitalPortal\Helpers\ApiResponse;
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use Illuminate\Support\Facades\View;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class ProfileDoctorController extends Controller
|
||||||
|
{
|
||||||
|
public function getProfile()
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'user_id' => auth()->check() ? auth()->user()->id : null,
|
||||||
|
];
|
||||||
|
$user_id = auth()->check() ? auth()->user()->id : null;
|
||||||
|
//Get data Profile
|
||||||
|
$dataProfile = DB::table('users')
|
||||||
|
->join('persons','persons.id', '=', 'users.person_id')
|
||||||
|
->leftJoin('person_educations','person_educations.person_id', '=', 'persons.id')
|
||||||
|
->leftJoin('practitioners','practitioners.person_id', '=', 'persons.id')
|
||||||
|
->leftJoin('practitioner_roles','practitioner_roles.practitioner_id', '=', 'practitioners.id')
|
||||||
|
->where('users.id', '=', $user_id)
|
||||||
|
->select(
|
||||||
|
'persons.name',
|
||||||
|
DB::raw('
|
||||||
|
"Pediatrics" AS specialist
|
||||||
|
'),
|
||||||
|
DB::raw('
|
||||||
|
"4" AS rating
|
||||||
|
'),
|
||||||
|
'persons.name AS full_name',
|
||||||
|
'persons.birth_date as date_of_birth',
|
||||||
|
'persons.gender',
|
||||||
|
'persons.phone AS mobile_number',
|
||||||
|
'persons.email',
|
||||||
|
'practitioners.str_number',
|
||||||
|
'practitioners.exp_date_str',
|
||||||
|
'practitioner_roles.sip_number',
|
||||||
|
'practitioner_roles.exp_date_sip'
|
||||||
|
)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
//Name
|
||||||
|
$dataName = [
|
||||||
|
'name' => $dataProfile->name,
|
||||||
|
'specialist' => $dataProfile->specialist,
|
||||||
|
'rating' => $dataProfile->rating
|
||||||
|
];
|
||||||
|
$res_data['dataName'] = $dataName;
|
||||||
|
|
||||||
|
// Basic
|
||||||
|
$dataProfileBasic = [
|
||||||
|
'full_name' => $dataProfile->full_name,
|
||||||
|
'date_of_birth' => $dataProfile->date_of_birth ? date('d M Y', strtotime($dataProfile->date_of_birth)) : '',
|
||||||
|
'gender' => $dataProfile->gender
|
||||||
|
];
|
||||||
|
$res_data['dataProfileBasic'] = $dataProfileBasic;
|
||||||
|
|
||||||
|
//Contact
|
||||||
|
$dataProfileContact = [
|
||||||
|
'mobile_number' => $dataProfile->mobile_number,
|
||||||
|
'email' => $dataProfile->email
|
||||||
|
];
|
||||||
|
$res_data['dataProfileContact'] = $dataProfileContact;
|
||||||
|
|
||||||
|
//Education
|
||||||
|
$dataEdu = DB::table('users')
|
||||||
|
->join('persons','persons.id', '=', 'users.person_id')
|
||||||
|
->leftJoin('person_educations','person_educations.person_id', '=', 'persons.id')
|
||||||
|
->where('users.id', '=', $user_id)
|
||||||
|
->select(
|
||||||
|
'person_educations.level_id',
|
||||||
|
'person_educations.name',
|
||||||
|
'person_educations.start_date',
|
||||||
|
'person_educations.end_date',
|
||||||
|
)
|
||||||
|
->get();
|
||||||
|
$dataEducations = [];
|
||||||
|
foreach($dataEdu as $val)
|
||||||
|
{
|
||||||
|
$dataEducations[] = [
|
||||||
|
'level_id' => $val->level_id,
|
||||||
|
'name' => $val->name,
|
||||||
|
'start_date' => date('d/m/Y', strtotime($val->start_date)),
|
||||||
|
'end_date' => date('d/m/Y', strtotime($val->end_date)),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$res_data['dataEducations'] = $dataEducations;
|
||||||
|
|
||||||
|
//Work Experience
|
||||||
|
$dataWork = DB::table('users')
|
||||||
|
->join('persons','persons.id', '=', 'users.person_id')
|
||||||
|
->leftJoin('practitioners','practitioners.person_id', '=', 'persons.id')
|
||||||
|
->leftJoin('practitioner_roles','practitioner_roles.practitioner_id', '=', 'practitioners.id')
|
||||||
|
->leftJoin('organizations','organizations.id', '=', 'practitioner_roles.organization_id')
|
||||||
|
->where('users.id', '=', $user_id)
|
||||||
|
->select(
|
||||||
|
'organizations.name',
|
||||||
|
'practitioner_roles.period_start',
|
||||||
|
'practitioner_roles.period_end',
|
||||||
|
)
|
||||||
|
->get();
|
||||||
|
$dataWorkExperience = [];
|
||||||
|
foreach ($dataWork as $val)
|
||||||
|
{
|
||||||
|
$dataWorkExperience[] = [
|
||||||
|
'name' => $val->name ? $val->name : '',
|
||||||
|
'period' => $this->fWorkExperience($val->period_start, $val->period_end)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$res_data['dataWorkExperience'] = $dataWorkExperience;
|
||||||
|
|
||||||
|
//STR
|
||||||
|
$dataStr = [
|
||||||
|
'str_number' => $dataProfile->str_number,
|
||||||
|
'exp_date_str' => $dataProfile->exp_date_str ? date('d M Y', strtotime($dataProfile->exp_date_str)) : ''
|
||||||
|
];
|
||||||
|
$res_data['dataStr'] = $dataStr;
|
||||||
|
|
||||||
|
//SIP
|
||||||
|
$dataSip = [
|
||||||
|
'sip_number' => $dataProfile->sip_number,
|
||||||
|
'exp_date_sip' => $dataProfile->exp_date_sip ? date('d M Y', strtotime($dataProfile->exp_date_sip)) : ''
|
||||||
|
];
|
||||||
|
$res_data['dataSip'] = $dataSip;
|
||||||
|
|
||||||
|
return ApiResponse::apiResponse("Success", $res_data, trans('Message.success'), 200);
|
||||||
|
|
||||||
|
}
|
||||||
|
public function fWorkExperience($start, $end)
|
||||||
|
{
|
||||||
|
$startDateString = $start; // Tanggal dan waktu awal
|
||||||
|
$endDateString = $end ; // Tanggal dan waktu akhir
|
||||||
|
|
||||||
|
// Mengubah string tanggal ke timestamp UNIX
|
||||||
|
$startTime = strtotime($startDateString);
|
||||||
|
$endTime = strtotime($endDateString);
|
||||||
|
|
||||||
|
// Menghitung selisih waktu dalam detik
|
||||||
|
$timeDifference = $endTime - $startTime;
|
||||||
|
|
||||||
|
// Menghitung jumlah tahun, bulan, dan hari dari selisih waktu
|
||||||
|
$years = floor($timeDifference / (365 * 24 * 60 * 60));
|
||||||
|
$months = floor(($timeDifference - ($years * 365 * 24 * 60 * 60)) / (30 * 24 * 60 * 60));
|
||||||
|
$days = floor(($timeDifference - ($years * 365 * 24 * 60 * 60) - ($months * 30 * 24 * 60 * 60)) / (24 * 60 * 60));
|
||||||
|
|
||||||
|
// Formatkan hasilnya
|
||||||
|
$experience = '';
|
||||||
|
if ($years > 0) {
|
||||||
|
$experience .= $years . ' years ';
|
||||||
|
}
|
||||||
|
if ($months > 0) {
|
||||||
|
$experience .= $months . ' months ';
|
||||||
|
}
|
||||||
|
if ($days > 0) {
|
||||||
|
$experience .= $days . ' days';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $experience;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
360
Modules/Linksehat/Http/Controllers/Api/DuitkuController.php
Normal file
360
Modules/Linksehat/Http/Controllers/Api/DuitkuController.php
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Linksehat\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use App\Models\Organization;
|
||||||
|
use App\Models\Speciality;
|
||||||
|
use App\Models\Livechat;
|
||||||
|
use App\Models\Channel;
|
||||||
|
use App\Models\UserChannel;
|
||||||
|
use Illuminate\Contracts\Support\Renderable;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Routing\Controller;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Support\Facades\Redirect;
|
||||||
|
|
||||||
|
class DuitkuController extends Controller
|
||||||
|
{
|
||||||
|
public function configuration()
|
||||||
|
{
|
||||||
|
$duitkuConfig = new \Duitku\Config(env('API_KEY_DUITKU'), env('CODE_MERCHANT_DUITKU'));
|
||||||
|
// false for production mode
|
||||||
|
// true for sandbox mode
|
||||||
|
$duitkuConfig->setSandboxMode(true);
|
||||||
|
// set sanitizer (default : true)
|
||||||
|
$duitkuConfig->setSanitizedMode(false);
|
||||||
|
// set log parameter (default : true)
|
||||||
|
$duitkuConfig->setDuitkuLogs(false);
|
||||||
|
return $duitkuConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createInvoice(Request $request)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'paymentMethod' => $request->paymentMethod,
|
||||||
|
'paymentAmount' => $request->paymentAmount,
|
||||||
|
'email' => $request->email,
|
||||||
|
'phoneNumber' => $request->phoneNumber,
|
||||||
|
'productDetails' => $request->productDetails,
|
||||||
|
'merchantOrderId' => $request->merchantOrderId,
|
||||||
|
'additionalParam' => $request->additionalParam,
|
||||||
|
'merchantUserInfo' => $request->merchantUserInfo,
|
||||||
|
'customerVaName' => $request->customerVaName,
|
||||||
|
// 'callbackUrl' => $request->callbackUrl,
|
||||||
|
// 'returnUrl' => $request->returnUrl,
|
||||||
|
// 'expiryPeriod' => $request->expiryPeriod,
|
||||||
|
'firstName' => $request->firstName,
|
||||||
|
'lastName' => $request->lastName,
|
||||||
|
'alamat' => $request->alamat,
|
||||||
|
'city' => $request->city,
|
||||||
|
'postalCode' => $request->postalCode,
|
||||||
|
// 'countryCode' => $request->countryCode
|
||||||
|
];
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'paymentMethod' => 'nullable',
|
||||||
|
'paymentAmount' => 'required',
|
||||||
|
'email' => 'required|email',
|
||||||
|
'phoneNumber' => 'nullable',
|
||||||
|
'productDetails' => 'required',
|
||||||
|
'merchantOrderId' => 'required',
|
||||||
|
'additionalParam' => 'nullable',
|
||||||
|
'merchantUserInfo' => 'nullable',
|
||||||
|
'customerVaName' => 'required',
|
||||||
|
// 'callbackUrl' => 'required',
|
||||||
|
// 'returnUrl' => 'nullable',
|
||||||
|
// 'expiryPeriod' => 'required',
|
||||||
|
'firstName' => 'required',
|
||||||
|
'lastName' => 'required',
|
||||||
|
'alamat' => 'required',
|
||||||
|
'city' => 'required',
|
||||||
|
'postalCode' => 'required',
|
||||||
|
// 'countryCode' => 'required'
|
||||||
|
|
||||||
|
], [
|
||||||
|
'paymentAmount.required' => 'Jumlah pembayaran harus diisi',
|
||||||
|
'email.required' => 'Email harus diisi',
|
||||||
|
'email.email' => 'Format email salah',
|
||||||
|
'productDetails.required' => 'Judul pembayaran harus diisi',
|
||||||
|
'merchantOrderId.required' => 'Order ID harus diisi',
|
||||||
|
'customerVaName.required' => 'Nama panggilan pelanggan harus diisi',
|
||||||
|
'firstName.required' => 'Nama depan pelanggan harus diisi',
|
||||||
|
'lastName.required' => 'Nama belakang pelanggan harus diisi',
|
||||||
|
'alamat.required' => 'Alamat pelanggan harus diisi',
|
||||||
|
'city.required' => 'Kota pelanggan harus diisi',
|
||||||
|
'postalCode.required' => 'Kode pos pelanggan harus diisi',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails())
|
||||||
|
{
|
||||||
|
return Helper::responseJson(
|
||||||
|
data: $data,
|
||||||
|
status: 'Bad Request',
|
||||||
|
statusCode: 400,
|
||||||
|
message: $validator->errors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#CONTOH DARI DUITKU
|
||||||
|
// $paymentMethod = ""; // PaymentMethod list => https://docs.duitku.com/pop/id/#payment-method
|
||||||
|
// $paymentAmount = 10000; // Amount
|
||||||
|
// $email = "customer@gmail.com"; // your customer email
|
||||||
|
// $phoneNumber = "081234567890"; // your customer phone number (optional)
|
||||||
|
// $productDetails = "Test Payment";
|
||||||
|
// $merchantOrderId = "2"; // from merchant, unique
|
||||||
|
// $additionalParam = ''; // optional
|
||||||
|
// $merchantUserInfo = ''; // optional
|
||||||
|
// $customerVaName = 'John Doe'; // display name on bank confirmation display
|
||||||
|
// $callbackUrl = 'http://YOUR_SERVER/callback'; // url for callback
|
||||||
|
// $returnUrl = 'http://YOUR_SERVER/return'; // url for redirect
|
||||||
|
// $expiryPeriod = 60; // set the expired time in minutes
|
||||||
|
|
||||||
|
// // Customer Detail
|
||||||
|
// $firstName = "John";
|
||||||
|
// $lastName = "Doe";
|
||||||
|
|
||||||
|
// // Address
|
||||||
|
// $alamat = "Jl. Kembangan Raya";
|
||||||
|
// $city = "Jakarta";
|
||||||
|
// $postalCode = "11530";
|
||||||
|
// $countryCode = "ID";
|
||||||
|
|
||||||
|
$paymentMethod = $request->paymentMethod; // PaymentMethod list => https://docs.duitku.com/pop/id/#payment-method
|
||||||
|
$paymentAmount = $request->paymentAmount; // Amount
|
||||||
|
$email = $request->email; // your customer email
|
||||||
|
$phoneNumber = $request->phoneNumber; // your customer phone number (optional)
|
||||||
|
$productDetails = $request->productDetails;
|
||||||
|
$merchantOrderId = $request->merchantOrderId; // from merchant, unique
|
||||||
|
$additionalParam = $request->additionalParam; // optional
|
||||||
|
$merchantUserInfo = $request->merchantUserInfo; // optional
|
||||||
|
$customerVaName = $request->customerVaName; // display name on bank confirmation display
|
||||||
|
$callbackUrl = env('APP_URL').'/api/linksehat/callback-duitku'; // url for callback
|
||||||
|
$returnUrl = env('APP_URL').'/api/linksehat/redirect-duitku';; // url for redirect
|
||||||
|
$expiryPeriod = 60; // set the expired time in minutes
|
||||||
|
|
||||||
|
// Customer Detail
|
||||||
|
$firstName = $request->firstName;
|
||||||
|
$lastName = $request->lastName;
|
||||||
|
|
||||||
|
// Address
|
||||||
|
$alamat = $request->alamat;
|
||||||
|
$city = $request->city;
|
||||||
|
$postalCode = $request->postalCode;
|
||||||
|
$countryCode = "ID";
|
||||||
|
|
||||||
|
$address = array(
|
||||||
|
'firstName' => $firstName,
|
||||||
|
'lastName' => $lastName,
|
||||||
|
'address' => $alamat,
|
||||||
|
'city' => $city,
|
||||||
|
'postalCode' => $postalCode,
|
||||||
|
'phone' => $phoneNumber,
|
||||||
|
'countryCode' => $countryCode
|
||||||
|
);
|
||||||
|
|
||||||
|
$customerDetail = array(
|
||||||
|
'firstName' => $firstName,
|
||||||
|
'lastName' => $lastName,
|
||||||
|
'email' => $email,
|
||||||
|
'phoneNumber' => $phoneNumber,
|
||||||
|
'billingAddress' => $address,
|
||||||
|
'shippingAddress' => $address
|
||||||
|
);
|
||||||
|
|
||||||
|
// Item Details
|
||||||
|
$item1 = array(
|
||||||
|
'name' => $productDetails,
|
||||||
|
'price' => $paymentAmount,
|
||||||
|
'quantity' => 1
|
||||||
|
);
|
||||||
|
|
||||||
|
$itemDetails = array(
|
||||||
|
$item1
|
||||||
|
);
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'paymentAmount' => $paymentAmount,
|
||||||
|
'merchantOrderId' => $merchantOrderId,
|
||||||
|
'productDetails' => $productDetails,
|
||||||
|
'additionalParam' => $additionalParam,
|
||||||
|
'merchantUserInfo' => $merchantUserInfo,
|
||||||
|
'customerVaName' => $customerVaName,
|
||||||
|
'email' => $email,
|
||||||
|
'phoneNumber' => $phoneNumber,
|
||||||
|
'itemDetails' => $itemDetails,
|
||||||
|
'customerDetail' => $customerDetail,
|
||||||
|
'callbackUrl' => $callbackUrl,
|
||||||
|
'returnUrl' => $returnUrl,
|
||||||
|
'expiryPeriod' => $expiryPeriod
|
||||||
|
);
|
||||||
|
$duitkuConfig = $this->configuration();
|
||||||
|
try {
|
||||||
|
// createInvoice Request
|
||||||
|
$responseDuitkuPop = \Duitku\Pop::createInvoice($params, $duitkuConfig);
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo $responseDuitkuPop;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo $e->getMessage();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function paymentMethod(Request $request)
|
||||||
|
{
|
||||||
|
$duitkuConfig = $this->configuration();
|
||||||
|
try {
|
||||||
|
$paymentAmount = "10000"; //"YOUR_AMOUNT";
|
||||||
|
$paymentMethodList = \Duitku\Pop::getPaymentMethod($paymentAmount, $duitkuConfig);
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo $paymentMethodList;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkStatus(Request $request)
|
||||||
|
{
|
||||||
|
$duitkuConfig = $this->configuration();
|
||||||
|
$data = [
|
||||||
|
'merchantOrderId' => $request->merchantOrderId
|
||||||
|
];
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'merchantOrderId' => 'required',
|
||||||
|
], [
|
||||||
|
'merchantOrderId.required' => 'Order ID harus diisi',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails())
|
||||||
|
{
|
||||||
|
return Helper::responseJson(
|
||||||
|
data: $data,
|
||||||
|
status: 'Bad Request',
|
||||||
|
statusCode: 400,
|
||||||
|
message: $validator->errors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$merchantOrderId = $request->merchantOrderId;
|
||||||
|
$transactionList = \Duitku\Pop::transactionStatus($merchantOrderId, $duitkuConfig);
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
$transaction = json_decode($transactionList);
|
||||||
|
|
||||||
|
// var_dump($transactionList);
|
||||||
|
|
||||||
|
if ($transaction->statusCode == "00") {
|
||||||
|
// Action Success
|
||||||
|
} else if ($transaction->statusCode == "01") {
|
||||||
|
// Action Pending
|
||||||
|
} else {
|
||||||
|
// Action Failed Or Expired
|
||||||
|
}
|
||||||
|
echo $transaction->statusCode;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function callback(Request $request)
|
||||||
|
{
|
||||||
|
$duitkuConfig = $this->configuration();
|
||||||
|
try {
|
||||||
|
$callback = \Duitku\Pop::callback($duitkuConfig);
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
$notif = json_decode($callback);
|
||||||
|
|
||||||
|
// $notif = $request; ini untuk di local
|
||||||
|
|
||||||
|
DB::table('api_logs')
|
||||||
|
->insert([
|
||||||
|
'type' => 'in',
|
||||||
|
'target' => env('APP_URL').'/api/linksehat/callback-duitku',
|
||||||
|
'request' => $callback,
|
||||||
|
'created_by' => auth()->check() ? auth()->user()->id : null,
|
||||||
|
'created_at' => date('Y-m-d H:i:s')
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($notif->resultCode == "00") {
|
||||||
|
// Action Success
|
||||||
|
$livechat = Livechat::where('uuid', $notif->merchantOrderId)->first();
|
||||||
|
// Update status pembayaran
|
||||||
|
$livechat->payment_method = $notif->paymentCode;
|
||||||
|
$livechat->status = 5; // success payment
|
||||||
|
$livechat->save();
|
||||||
|
|
||||||
|
// Update start chat
|
||||||
|
$livechat->start_date = date('Y-m-d H:i:s');
|
||||||
|
// 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
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Berikan respons yang sesuai ke klien
|
||||||
|
return response()->json(['message' => 'Channel created successfully', 'channel' => $channel]);
|
||||||
|
|
||||||
|
} else if ($notif->resultCode == "01") {
|
||||||
|
// Action Failed
|
||||||
|
$livechat = Livechat::where('uuid', $notif->merchantOrderId)->first();
|
||||||
|
// Update status pembayaran
|
||||||
|
$livechat->payment_method = $notif->paymentCode;
|
||||||
|
$livechat->status = 7; // failed payment
|
||||||
|
$livechat->save();
|
||||||
|
|
||||||
|
return response()->json(['message' => 'User Gagal melakukan pembayaran']);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function redirect(Request $request)
|
||||||
|
{
|
||||||
|
$resultCode = $request->input('resultCode');
|
||||||
|
$merchantOrderId = $request->input('merchantOrderId');
|
||||||
|
$reference = $request->input('reference');
|
||||||
|
return Redirect::to('https://linksehat.com/');
|
||||||
|
}
|
||||||
|
}
|
||||||
75
Modules/Linksehat/Http/Controllers/Api/HomeController.php
Normal file
75
Modules/Linksehat/Http/Controllers/Api/HomeController.php
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Linksehat\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use App\Models\Organization;
|
||||||
|
use App\Models\PractitionerRole;
|
||||||
|
use App\Models\OLDLMS\User;
|
||||||
|
use Illuminate\Routing\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Modules\Linksehat\Transformers\Article\ArticleResource;
|
||||||
|
use Modules\Linksehat\Transformers\Home\HomeResource;
|
||||||
|
use Modules\Linksehat\Transformers\Doctor\DoctorResource;
|
||||||
|
use Modules\Linksehat\Transformers\Hospital\HospitalResource;
|
||||||
|
|
||||||
|
class HomeController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$user = User::with('detail')
|
||||||
|
->where('nId', $request->id)
|
||||||
|
->first();
|
||||||
|
return Helper::responseJson([
|
||||||
|
'home' => HomeResource::make($user, $request),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listHospital(Request $request){
|
||||||
|
// Hospital List
|
||||||
|
$hospitalList = [];
|
||||||
|
$hospitals = Organization::where([
|
||||||
|
'type' => 'hospital',
|
||||||
|
'status' => 'active',
|
||||||
|
])
|
||||||
|
->with('currentAddress')
|
||||||
|
->get()->toArray();
|
||||||
|
foreach($hospitals as $hospital){
|
||||||
|
$lat = 0;
|
||||||
|
$lang = 0;
|
||||||
|
if ($hospital['current_address']['lat']){
|
||||||
|
$lat = $hospital['current_address']['lat'];
|
||||||
|
}
|
||||||
|
if ($hospital['current_address']['lng']){
|
||||||
|
$lang = $hospital['current_address']['lng'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$address = '';
|
||||||
|
if ($hospital['current_address']['text']){
|
||||||
|
$address = $hospital['current_address']['text'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$radius = 0;
|
||||||
|
if ($lat && $lang && $request->longitude && $request->latitude){
|
||||||
|
$radius = round(Helper::calculateDistance($lat, $lang, $request->latitude, $request->longitude), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name' => $hospital['name'],
|
||||||
|
'radius' => $radius,
|
||||||
|
'image' => '',
|
||||||
|
'address' => $address
|
||||||
|
];
|
||||||
|
|
||||||
|
array_push($hospitalList, $data);
|
||||||
|
}
|
||||||
|
usort($hospitalList, function($a, $b) {
|
||||||
|
return $a['radius'] <=> $b['radius'];
|
||||||
|
});
|
||||||
|
return Helper::responseJson([
|
||||||
|
'hospital' => $hospitalList
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@ namespace Modules\Linksehat\Http\Controllers\Api;
|
|||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Person;
|
use App\Models\Person;
|
||||||
|
use App\Models\RequestLogBenefit;
|
||||||
|
use App\Models\RequestLog;
|
||||||
use App\Models\Corporate;
|
use App\Models\Corporate;
|
||||||
use App\Models\Member;
|
use App\Models\Member;
|
||||||
use App\Models\OLDLMS\User;
|
use App\Models\OLDLMS\User;
|
||||||
@@ -135,4 +137,39 @@ class LinkingController extends Controller
|
|||||||
$message = $member->currentPolicy->corporate->welcome_message;
|
$message = $member->currentPolicy->corporate->welcome_message;
|
||||||
return Helper::responseJson(data: MemberResource::make($member), message: $message);
|
return Helper::responseJson(data: MemberResource::make($member), message: $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function card_detail($member_id, $id){
|
||||||
|
$member = Member::where('member_id', $member_id)->get()->toArray();
|
||||||
|
$requestLogBenefits = RequestLogBenefit::where('request_log_id', $id)->with('benefit')->get()->toArray();
|
||||||
|
$requestLog = RequestLog::find($id)->first();
|
||||||
|
$benefitItem = [];
|
||||||
|
$dataRequestLog = [
|
||||||
|
'code' => $requestLog['code'],
|
||||||
|
'diagnosis' => Helper::diagnosisName($requestLog['diagnosis']),
|
||||||
|
'service_type' => Helper::serviceName($requestLog['service_code']),
|
||||||
|
|
||||||
|
];
|
||||||
|
foreach($requestLogBenefits as $requestLogBenefit) {
|
||||||
|
$data = [
|
||||||
|
'benefit_item' => $requestLogBenefit['benefit']['description'],
|
||||||
|
'amount_incurred' => $requestLogBenefit['amount_incurred'],
|
||||||
|
'amount_approved' => $requestLogBenefit['amount_approved'],
|
||||||
|
'amount_not_approved' => $requestLogBenefit['amount_not_approved'],
|
||||||
|
'excess_paid' => $requestLogBenefit['excess_paid'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$benefitItem[] = $data;
|
||||||
|
};
|
||||||
|
$dataRequestLog['benefit_item'] = $benefitItem;
|
||||||
|
|
||||||
|
// dd($dataRequestLog);
|
||||||
|
// $data = [
|
||||||
|
// 'id' => $requestLog['id'],
|
||||||
|
// 'code' => $requestLog['code'],
|
||||||
|
// 'submission_date' => Carbon::parse($requestLog['submission_date'])->format('d M Y H:i:s'),
|
||||||
|
// 'provider_name' => $requestLog['organization']['name'],
|
||||||
|
// 'service' => Helper::serviceName($requestLog['service_code'])
|
||||||
|
// ];
|
||||||
|
return Helper::responseJson(data:$dataRequestLog);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
308
Modules/Linksehat/Http/Controllers/Api/LivechatController.php
Normal file
308
Modules/Linksehat/Http/Controllers/Api/LivechatController.php
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Linksehat\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use App\Helpers\DuitkuHelper;
|
||||||
|
use App\Services\Duitku;
|
||||||
|
use App\Models\Organization;
|
||||||
|
use App\Models\PractitionerRole;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\PaymentsMethods;
|
||||||
|
use App\Models\Livechat;
|
||||||
|
use App\Models\OLDLMS\User;
|
||||||
|
use Illuminate\Routing\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Modules\Linksehat\Transformers\Livechat\LivechatResource;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use App\Http\Controllers\DuitkuController;
|
||||||
|
|
||||||
|
use DB;
|
||||||
|
use Str;
|
||||||
|
|
||||||
|
class LivechatController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$user = User::with('detail')
|
||||||
|
->where('nId', $request->id)
|
||||||
|
->first();
|
||||||
|
return Helper::responseJson([
|
||||||
|
'livechat' => LivechatResource::make($user, $request),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function consultation(Request $request)
|
||||||
|
{
|
||||||
|
$dataMemberProfile = [];
|
||||||
|
$user = User::with('detail')
|
||||||
|
->where('nId', $request->member_id)
|
||||||
|
->first();
|
||||||
|
$memberProfile = User::with('detail')->where('nIDUser', $request->member_id)->get()->toArray();
|
||||||
|
if (count($memberProfile) > 0){
|
||||||
|
$urlAvatarDefault = $user->detail->nIDJenisKelamin == 1 ? 'https://linksehat.dev/assets/img/users/male-avatar.png' : 'https://linksehat.dev/assets/img/users/female-avatar.png';
|
||||||
|
$avatarMember = $user->detail->sImage ?? $urlAvatarDefault;
|
||||||
|
$relationship = DB::connection('oldlms')->table('tm_hubungan_keluarga')->where('nID', $user->nIDHubunganKeluarga)->first('sHubunganKeluarga');
|
||||||
|
|
||||||
|
$dataUser = [
|
||||||
|
'id' => $user->nID,
|
||||||
|
'name' => $user->sFirstName . ' ' . $user->sLastName,
|
||||||
|
'relationship' => $relationship ? $relationship->sHubunganKeluarga : '-',
|
||||||
|
'avatar' => $avatarMember
|
||||||
|
];
|
||||||
|
|
||||||
|
array_push($dataMemberProfile, $dataUser);
|
||||||
|
|
||||||
|
foreach($memberProfile as $m){
|
||||||
|
$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 ? $relationship->sHubunganKeluarga : '-',
|
||||||
|
'avatar' => $avatarMember,
|
||||||
|
];
|
||||||
|
|
||||||
|
array_push($dataMemberProfile, $data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$nID = $user->nIDUser ? $user->nIDUser : $user->nID;
|
||||||
|
if ($nID){
|
||||||
|
$memberProfile = User::with('detail')->where('nIDUser', $nID)->get()->toArray();
|
||||||
|
|
||||||
|
$dataMember = User::with('detail')->where('nID', $nID)->get()->first();
|
||||||
|
|
||||||
|
if ($user->detail){
|
||||||
|
$urlAvatarDefault = $user->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 = $user->detail->sImage ?? $urlAvatarDefault;
|
||||||
|
|
||||||
|
$avatarMember = $dataMember->detail->sImage ?? $urlAvatarDefault;
|
||||||
|
$relationship = DB::connection('oldlms')->table('tm_hubungan_keluarga')->where('nID', $user->detail->nIDHubunganKeluarga)->first('sHubunganKeluarga');
|
||||||
|
|
||||||
|
$dataUser = [
|
||||||
|
'id' => $dataMember->nID,
|
||||||
|
'name' => $dataMember->sFirstName . ' ' . $dataMember->sLastName,
|
||||||
|
'relationship' => 'Me',
|
||||||
|
'avatar' => $avatarMember
|
||||||
|
];
|
||||||
|
array_push($dataMemberProfile, $dataUser);
|
||||||
|
|
||||||
|
if (count($memberProfile) > 0){
|
||||||
|
foreach($memberProfile as $m){
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Helper::responseJson([
|
||||||
|
'member' => $dataMemberProfile
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function consultation_request(Request $request)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'doctor_id' => $request->doctor_id,
|
||||||
|
'patient_id' => $request->patient_id,
|
||||||
|
'organization_id' => $request->organization_id,
|
||||||
|
'descriptions' => $request->descriptions
|
||||||
|
];
|
||||||
|
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'doctor_id' => 'required',
|
||||||
|
'patient_id' => 'required',
|
||||||
|
'descriptions' => 'required',
|
||||||
|
], [
|
||||||
|
'doctor_id.required' => 'ID Dokter harus diisi',
|
||||||
|
'patient_id.required' => 'ID Dokter harus diisi',
|
||||||
|
'descriptions.required' => 'Description harus diisi',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()){
|
||||||
|
return Helper::responseJson(
|
||||||
|
status: 'Bad Request',
|
||||||
|
statusCode: 400,
|
||||||
|
message: $validator->errors()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// insert table livechat
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status Livechat
|
||||||
|
* 1=Request, 2=Accept, 3=Decline, 4=Waiting Payment, 5=Success Payment, 6 = End Chat
|
||||||
|
*/
|
||||||
|
|
||||||
|
$timezone = date_default_timezone_get();
|
||||||
|
$data['request_date'] = date('Y-m-d H:i:s');
|
||||||
|
$data['timezone'] = $timezone;
|
||||||
|
$data['uuid'] = (string) Str::orderedUuid();
|
||||||
|
$data['status'] = 1;
|
||||||
|
$livechat = Livechat::create($data);
|
||||||
|
$doctor = $livechat->doctor;
|
||||||
|
$data = [
|
||||||
|
'id' => $livechat->id,
|
||||||
|
'request_date' => $livechat->request_date,
|
||||||
|
'image_path' =>'https'
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
return Helper::responseJson(data: $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function consultation_request_show($id){
|
||||||
|
$livechat = Livechat::where('id', $id)->with(['doctor', 'practitioner'])->first();
|
||||||
|
$practitionerRole = PractitionerRole::where('id',$livechat->practitioner->id)->first();
|
||||||
|
|
||||||
|
$price = $practitionerRole->price ? $practitionerRole->price : 30000;
|
||||||
|
$discount = 0;
|
||||||
|
$adminFee = 5000;
|
||||||
|
$totalPay = $price + $adminFee - $discount;
|
||||||
|
$data = [
|
||||||
|
'id' => $livechat->id,
|
||||||
|
'code_transaksi' => $livechat->uuid,
|
||||||
|
'doctor_id' => $livechat->doctor_id,
|
||||||
|
'doctor_name' => $livechat->doctor->name,
|
||||||
|
'doctor_specialist' => 'Umum',
|
||||||
|
'price' => $price,
|
||||||
|
'admin_price' => $adminFee,
|
||||||
|
'promo' => [
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'code' => 'SEHATBERSAMA',
|
||||||
|
'discount_percent' => 20
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 2,
|
||||||
|
'code' => 'MARET MERIAH',
|
||||||
|
'discount_percent' => 5
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'total' => $totalPay
|
||||||
|
|
||||||
|
];
|
||||||
|
return Helper::responseJson(data: $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function consultation_payment_choose($id){
|
||||||
|
$livechat = Livechat::where('id', $id)->with(['doctor', 'practitioner'])->first();
|
||||||
|
$practitionerRole = PractitionerRole::where('id',$livechat->practitioner->id)->first();
|
||||||
|
$eWallet = PaymentsMethods::where(
|
||||||
|
[
|
||||||
|
'active' => 1,
|
||||||
|
'config_pmc_id' => 3,
|
||||||
|
])->get()->toArray();
|
||||||
|
$va = PaymentsMethods::where(
|
||||||
|
[
|
||||||
|
'active' => 1,
|
||||||
|
'config_pmc_id' => 2,
|
||||||
|
])->get()->toArray();
|
||||||
|
|
||||||
|
$payment = DuitkuHelper::paymentMethod();
|
||||||
|
|
||||||
|
$price = $practitionerRole->price ? $practitionerRole->price : 30000;
|
||||||
|
$discount = 0;
|
||||||
|
$adminFee = 5000;
|
||||||
|
$totalPay = $price + $adminFee - $discount;
|
||||||
|
$data = [
|
||||||
|
'id' => $livechat->id,
|
||||||
|
'code_transaksi' => $livechat->uuid,
|
||||||
|
'price' => $price,
|
||||||
|
'admin_price' => $adminFee,
|
||||||
|
'total' => $totalPay,
|
||||||
|
'payment_method' => [
|
||||||
|
'ewallet' => $eWallet,
|
||||||
|
'va' => $va
|
||||||
|
]
|
||||||
|
// 'payment_method' => json_decode($payment)
|
||||||
|
|
||||||
|
];
|
||||||
|
return Helper::responseJson(data: $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function consultation_payment(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Mengambil data Livechat dengan relasi doctor dan practitioner
|
||||||
|
$livechat = Livechat::with(['doctor', 'practitioner'])->find($request->consultation_id);
|
||||||
|
|
||||||
|
if (!$livechat) {
|
||||||
|
return response()->json(['success' => false, 'message' => 'Consultation not found'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update status
|
||||||
|
$livechat->status = 4;
|
||||||
|
$livechat->save();
|
||||||
|
|
||||||
|
$practitionerRole = PractitionerRole::find($livechat->practitioner->id);
|
||||||
|
$price = $practitionerRole->price ?? 30000; // Gunakan null coalescing operator
|
||||||
|
$adminFee = 5000;
|
||||||
|
$discount = 0;
|
||||||
|
$totalPay = $price + $adminFee - $discount;
|
||||||
|
|
||||||
|
// Mengambil user dari database
|
||||||
|
$user = User::with('detail')->where('nId', $livechat->patient_id)->first();
|
||||||
|
$address = DB::connection('oldlms')->table('tm_users_address')->where('nIDUser', $user->nID)->first('sAlamat');
|
||||||
|
if($address){
|
||||||
|
$address = $address->sAlamat;
|
||||||
|
}
|
||||||
|
if (!$user) {
|
||||||
|
return response()->json(['success' => false, 'message' => 'User not found'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Menyiapkan data untuk invoice
|
||||||
|
$data = [
|
||||||
|
'paymentMethod' => $request->payment_code,
|
||||||
|
'paymentAmount' => $totalPay,
|
||||||
|
'email' => $user->sEmail,
|
||||||
|
'phoneNumber' => $user->sPhone,
|
||||||
|
'productDetails' => 'INV-' . date('Ymd') . '-' . rand(100, 999),
|
||||||
|
'merchantOrderId' => $livechat->uuid,
|
||||||
|
'additionalParam' => '',
|
||||||
|
'merchantUserInfo' => '',
|
||||||
|
'customerVaName' => $user->sFirstName . ' ' . $user->sLastName,
|
||||||
|
'firstName' => $user->sFirstName,
|
||||||
|
'lastName' => $user->sLastName,
|
||||||
|
'alamat' => $address,
|
||||||
|
'city' => '',
|
||||||
|
'postalCode' => ''
|
||||||
|
];
|
||||||
|
|
||||||
|
// Membuat invoice menggunakan DuitkuHelper
|
||||||
|
$duitku = DuitkuHelper::createInvoice($data);
|
||||||
|
|
||||||
|
|
||||||
|
return response()->json(['success' => true, 'data' => $duitku], 200);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Menangkap error dan mengembalikan respon error
|
||||||
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function consultation_check_payment($id){
|
||||||
|
$livechat = Livechat::where('id',$id)->with(['doctor', 'practitioner'])->first();
|
||||||
|
$duitku = DuitkuHelper::checkStatus($livechat->uuid);
|
||||||
|
|
||||||
|
return $duitku;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,46 @@ class ProfileController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
//
|
$validator = Validator::make($request->all(), [
|
||||||
|
'id_user' => 'required',
|
||||||
|
'first_name' => 'required',
|
||||||
|
'last_name' => 'required',
|
||||||
|
'date_of_birth' => 'required',
|
||||||
|
// 'email' => 'required',
|
||||||
|
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json(['errors' => $validator->errors()], 422);
|
||||||
|
} else {
|
||||||
|
$value = [
|
||||||
|
'nIDuser' => $request->id_user,
|
||||||
|
'sIPAddress' => $request->ip(),
|
||||||
|
'sPassword' => null,
|
||||||
|
'sFirstName' => $request->first_name,
|
||||||
|
'sLastName' => $request->last_name,
|
||||||
|
];
|
||||||
|
|
||||||
|
$user = User::create($value);
|
||||||
|
$dataDetail = [
|
||||||
|
'nIDUser' => $user->nID,
|
||||||
|
'dTanggalLahir' => $request->date_of_birth,
|
||||||
|
'nIDJenisKelamin' => $request->gender
|
||||||
|
];
|
||||||
|
|
||||||
|
$userDetail = UserDetail::create(
|
||||||
|
$dataDetail
|
||||||
|
);
|
||||||
|
|
||||||
|
$data['data'] = [
|
||||||
|
'status' => 200,
|
||||||
|
'message' => 'data berhasil di tambahkan',
|
||||||
|
'error' => 'false'
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
return response()->json($data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
65
Modules/Linksehat/Http/Middleware/Doctor/Authentication.php
Normal file
65
Modules/Linksehat/Http/Middleware/Doctor/Authentication.php
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Linksehat\Http\Middleware\Doctor;
|
||||||
|
use Modules\Linksehat\Helpers\Doctor\ApiResponse;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
|
||||||
|
class Authentication
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||||
|
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
$acceptHeader = $request->header('Accept');
|
||||||
|
$contentType = $request->header('Content-Type');
|
||||||
|
$locale = $request->header('Accept-Language');
|
||||||
|
|
||||||
|
// Add language
|
||||||
|
if(!$locale)
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Unauthorized', null, trans('Validation.required', ['attribute' => 'Accept-Language']), 401);
|
||||||
|
}
|
||||||
|
if($locale !== 'en-US' && $locale !== 'id-ID')
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Bad Request', null, trans('Validation.invalid', ['attribute' => 'Accept-Language']), 400);
|
||||||
|
}
|
||||||
|
if ($locale === 'en-US')
|
||||||
|
{
|
||||||
|
App::setLocale('en');
|
||||||
|
} elseif ($locale === 'id-ID')
|
||||||
|
{
|
||||||
|
App::setLocale('id');
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
App::setLocale('en');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate type accept & content type
|
||||||
|
if (!$acceptHeader)
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Unauthorized', null, trans('Validation.required', ['attribute' => 'Accept']), 401);
|
||||||
|
}
|
||||||
|
if (!$contentType)
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Unauthorized', null, trans('Validation.required', ['attribute' => 'Content-Type']), 401);
|
||||||
|
}
|
||||||
|
if ($acceptHeader !== 'application/json')
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Bad Request', null, trans('Validation.invalid', ['attribute' => 'Accept']), 400);
|
||||||
|
}
|
||||||
|
if($contentType !== 'application/json')
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Bad Request', null, trans('Validation.invalid', ['attribute' => 'Content-Type']), 400);
|
||||||
|
}
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
71
Modules/Linksehat/Http/Middleware/Doctor/Authorization.php
Normal file
71
Modules/Linksehat/Http/Middleware/Doctor/Authorization.php
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Linksehat\Http\Middleware\Doctor;
|
||||||
|
use Modules\Linksehat\Helpers\Doctor\ApiResponse;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
|
||||||
|
class Authorization
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||||
|
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
$acceptHeader = $request->header('Accept');
|
||||||
|
$contentType = $request->header('Content-Type');
|
||||||
|
$locale = $request->header('Accept-Language');
|
||||||
|
$authorization = $request->header('Authorization');
|
||||||
|
|
||||||
|
// Add language
|
||||||
|
if(!$locale)
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Unauthorized', null, trans('Validation.required', ['attribute' => 'Accept-Language']), 401);
|
||||||
|
}
|
||||||
|
if($locale !== 'en-US' && $locale !== 'id-ID')
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Bad Request', null, trans('Validation.invalid', ['attribute' => 'Accept-Language']), 400);
|
||||||
|
}
|
||||||
|
if ($locale === 'en-US')
|
||||||
|
{
|
||||||
|
App::setLocale('en');
|
||||||
|
} elseif ($locale === 'id-ID')
|
||||||
|
{
|
||||||
|
App::setLocale('id');
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
App::setLocale('en');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate authorization
|
||||||
|
if (empty($authorization) || strpos($authorization, 'Bearer ') !== 0) {
|
||||||
|
return ApiResponse::apiResponse('Unauthorized', null, trans('Validation.required', ['attribute' => 'Authorization']), 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate type accept & content type
|
||||||
|
if (!$acceptHeader)
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Unauthorized', null, trans('Validation.required', ['attribute' => 'Accept']), 401);
|
||||||
|
}
|
||||||
|
if (!$contentType && $request->isMethod('post'))
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Unauthorized', null, trans('Validation.required', ['attribute' => 'Content-Type']), 401);
|
||||||
|
}
|
||||||
|
if ($acceptHeader !== 'application/json')
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Bad Request', null, trans('Validation.invalid', ['attribute' => 'Accept']), 400);
|
||||||
|
}
|
||||||
|
if($contentType !== 'application/json' && $request->isMethod('post'))
|
||||||
|
{
|
||||||
|
return ApiResponse::apiResponse('Bad Request', null, trans('Validation.invalid', ['attribute' => 'Content-Type']), 400);
|
||||||
|
}
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@ use Modules\Linksehat\Http\Controllers\Api\AuthController;
|
|||||||
use Modules\Linksehat\Http\Controllers\Api\DashboardController;
|
use Modules\Linksehat\Http\Controllers\Api\DashboardController;
|
||||||
use Modules\Linksehat\Http\Controllers\Api\AutocompleteController;
|
use Modules\Linksehat\Http\Controllers\Api\AutocompleteController;
|
||||||
use Modules\Linksehat\Http\Controllers\Api\DoctorController;
|
use Modules\Linksehat\Http\Controllers\Api\DoctorController;
|
||||||
|
use Modules\Linksehat\Http\Controllers\Api\DuitkuController;
|
||||||
|
use Modules\Linksehat\Http\Controllers\Api\ChatController;
|
||||||
use Modules\Linksehat\Http\Controllers\Api\HospitalController;
|
use Modules\Linksehat\Http\Controllers\Api\HospitalController;
|
||||||
use Modules\Linksehat\Http\Controllers\Api\NotificationTokenController;
|
use Modules\Linksehat\Http\Controllers\Api\NotificationTokenController;
|
||||||
use Modules\Linksehat\Http\Controllers\Api\PersonController;
|
use Modules\Linksehat\Http\Controllers\Api\PersonController;
|
||||||
@@ -12,7 +14,13 @@ use Modules\Linksehat\Http\Controllers\Api\ProfileController;
|
|||||||
use Modules\Linksehat\Http\Controllers\Api\SearchController;
|
use Modules\Linksehat\Http\Controllers\Api\SearchController;
|
||||||
use Modules\Linksehat\Http\Controllers\Api\SpecialityController;
|
use Modules\Linksehat\Http\Controllers\Api\SpecialityController;
|
||||||
use Modules\Linksehat\Http\Controllers\Api\LinkingController;
|
use Modules\Linksehat\Http\Controllers\Api\LinkingController;
|
||||||
|
use Modules\Linksehat\Http\Controllers\Api\HomeController;
|
||||||
|
use Modules\Linksehat\Http\Controllers\Api\LivechatController;
|
||||||
|
use Modules\Linksehat\Http\Middleware\Doctor\Authentication;
|
||||||
|
use Modules\Linksehat\Http\Middleware\Doctor\Authorization;
|
||||||
|
use Modules\Linksehat\Http\Controllers\Api\Doctor\AuthDoctorController;
|
||||||
|
use Modules\Linksehat\Http\Controllers\Api\Doctor\ProfileDoctorController;
|
||||||
|
use Modules\Linksehat\Http\Controllers\Api\Doctor\ChatDoctorController;
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| API Routes
|
| API Routes
|
||||||
@@ -24,6 +32,7 @@ use Modules\Linksehat\Http\Controllers\Api\LinkingController;
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
Broadcast::routes(['middleware' => ['auth:sanctum']]);
|
||||||
Route::prefix('linksehat')->group(function () {
|
Route::prefix('linksehat')->group(function () {
|
||||||
|
|
||||||
Route::get('dashboard/{query}/{limit?}', [DashboardController::class, 'index']);
|
Route::get('dashboard/{query}/{limit?}', [DashboardController::class, 'index']);
|
||||||
@@ -63,11 +72,11 @@ Route::prefix('linksehat')->group(function () {
|
|||||||
Route::get('doctors/{id}', 'show')->name('doctors.show');
|
Route::get('doctors/{id}', 'show')->name('doctors.show');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Route::middleware('auth:sanctum')->group(function () {
|
Route::middleware('auth:sanctum')->group(function () {
|
||||||
Route::get('profile/{id}', [ProfileController::class, 'index'])->name('profile');
|
Route::get('profile/{id}', [ProfileController::class, 'index'])->name('profile');
|
||||||
Route::get('change-profile/{id}', [ProfileController::class, 'changeProfile'])->name('change-profile');
|
Route::get('change-profile/{id}', [ProfileController::class, 'changeProfile'])->name('change-profile');
|
||||||
Route::post('profile', [ProfileController::class, 'update'])->name('profile.update');
|
Route::post('profile', [ProfileController::class, 'update'])->name('profile.update');
|
||||||
|
Route::post('profile-add', [ProfileController::class, 'store'])->name('profile.store');
|
||||||
Route::post('notification-tokens/delete/{id}', [NotificationTokenController::class, 'destroy'])->name('profile.delete.token');
|
Route::post('notification-tokens/delete/{id}', [NotificationTokenController::class, 'destroy'])->name('profile.delete.token');
|
||||||
Route::post('notification-tokens', [NotificationTokenController::class, 'store'])->name('profile.store.token');
|
Route::post('notification-tokens', [NotificationTokenController::class, 'store'])->name('profile.store.token');
|
||||||
Route::apiResource('appointment', AppointmentController::class);
|
Route::apiResource('appointment', AppointmentController::class);
|
||||||
@@ -77,10 +86,84 @@ Route::prefix('linksehat')->group(function () {
|
|||||||
Route::get('autocomplete/blood_type', [AutocompleteController::class, 'bloodType']);
|
Route::get('autocomplete/blood_type', [AutocompleteController::class, 'bloodType']);
|
||||||
Route::get('autocomplete/relationship', [AutocompleteController::class, 'relationship']);
|
Route::get('autocomplete/relationship', [AutocompleteController::class, 'relationship']);
|
||||||
Route::get('autocomplete/corporate', [AutocompleteController::class, 'corporate']);
|
Route::get('autocomplete/corporate', [AutocompleteController::class, 'corporate']);
|
||||||
|
Route::get('autocomplete/drugs', [AutocompleteController::class, 'drugList']);
|
||||||
|
Route::get('autocomplete/units', [AutocompleteController::class, 'unitList']);
|
||||||
|
Route::get('autocomplete/diagnosis', [AutocompleteController::class, 'diagnosis']);
|
||||||
|
|
||||||
Route::post('manual-linking', [LinkingController::class, 'linkingValidate']);
|
Route::post('manual-linking', [LinkingController::class, 'linkingValidate']);
|
||||||
|
|
||||||
Route::get('card/{member_id}', [LinkingController::class, 'card']);
|
Route::get('card/{member_id}', [LinkingController::class, 'card']);
|
||||||
|
Route::get('card/{member_id}/{log_id}', [LinkingController::class, 'card_detail']);
|
||||||
|
|
||||||
|
Route::controller(HomeController::class)->group(function () {
|
||||||
|
Route::get('home', 'index')->name('homes.index');
|
||||||
|
Route::get('home/hospital', 'listHospital')->name('homes.listHospital');
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::controller(LivechatController::class)->group(function () {
|
||||||
|
Route::get('livechat', 'index')->name('livechats.index');
|
||||||
|
Route::get('livechat/consultation', 'consultation')->name('livechats.consultation');
|
||||||
|
Route::post('livechat/consultation-request', 'consultation_request')->name('livechats.consultation-request');
|
||||||
|
Route::get('livechat/consultation-request/{id}', 'consultation_request_show');
|
||||||
|
Route::get('livechat/consultation-request/consultation-payment-choose/{id}', 'consultation_payment_choose');
|
||||||
|
Route::get('livechat/consultation-request/consultation-payment-check/{id}', 'consultation_check_payment');
|
||||||
|
|
||||||
|
Route::post('livechat/consultation-payment', 'consultation_payment');
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::controller(ChatController::class)->group(function () {
|
||||||
|
Route::post('livechat/send-message', 'sendMessage');
|
||||||
|
Route::get('livechat/get-message', 'getMessage');
|
||||||
|
Route::post('livechat/channel','createChannel');
|
||||||
|
Route::get('livechat/channel','listChannel');
|
||||||
|
Route::get('livechat/{id}/health-sertificate','downloadHealtcare');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Route::post('create-invoice-duitku', [DuitkuController::class, 'createInvoice']);
|
||||||
|
Route::post('check-status-duitku', [DuitkuController::class, 'checkStatus']);
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
Route::post('payment-method-duitku', [DuitkuController::class, 'paymentMethod']);
|
||||||
|
Route::post('callback-duitku', [DuitkuController::class, 'callback']);
|
||||||
|
Route::get('redirect-duitku', [DuitkuController::class, 'redirect']);
|
||||||
|
|
||||||
|
//DOCTOR API
|
||||||
|
Route::prefix('doctor')->group(function() {
|
||||||
|
//Version 1.0
|
||||||
|
Route::prefix('v1')->group(function() {
|
||||||
|
Route::middleware(Authentication::class)->group(function () {
|
||||||
|
Route::controller(AuthDoctorController::class)->group(function () {
|
||||||
|
Route::post('login', 'login');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Route::middleware('auth:sanctum')->group(function () {
|
||||||
|
Route::middleware(Authorization::class)->group(function () {
|
||||||
|
Route::controller(AuthDoctorController::class)->group(function () {
|
||||||
|
Route::post('logout', 'logout');
|
||||||
|
Route::post('forgot-password', 'forgotPassword');
|
||||||
|
});
|
||||||
|
Route::controller(ProfileDoctorController::class)->group(function () {
|
||||||
|
Route::get('get-profile', 'getProfile');
|
||||||
|
});
|
||||||
|
Route::controller(ChatDoctorController::class)->group(function () {
|
||||||
|
Route::get('chat', 'getChat');
|
||||||
|
Route::post('decline', 'declineChat');
|
||||||
|
Route::post('approve', 'approveChat');
|
||||||
|
Route::post('end', 'endChat');
|
||||||
|
Route::post('summary', 'summaryChat');
|
||||||
|
Route::get('chat/{id}', 'getChatDetail');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Route::controller(AuthDoctorController::class)->group(function () {
|
||||||
|
Route::post('forgot-password', 'forgotPassword');
|
||||||
|
Route::post('verif-code', 'verifCode');
|
||||||
|
Route::post('resend-code', 'forgotPassword');
|
||||||
|
Route::post('reset-password', 'resetPassword');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
;});
|
||||||
|
|||||||
280
Modules/Linksehat/Transformers/Home/HomeResource.php
Normal file
280
Modules/Linksehat/Transformers/Home/HomeResource.php
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Linksehat\Transformers\Home;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
use App\Models\OLDLMS\User;
|
||||||
|
use App\Models\OLDLMS\UserDetail;
|
||||||
|
use App\Models\OLDLMS\UserInsurance;
|
||||||
|
use App\Models\Organization;
|
||||||
|
use App\Models\Practitioner;
|
||||||
|
use App\Models\PractitionerRole;
|
||||||
|
use App\Models\Member;
|
||||||
|
use App\Models\Person;
|
||||||
|
use App\Models\CorporateEmployee;
|
||||||
|
use App\Models\Corporate;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use DB;
|
||||||
|
|
||||||
|
|
||||||
|
class HomeResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
protected $connection = 'oldlms';
|
||||||
|
|
||||||
|
public function __construct($resource, $request)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
parent::__construct($resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray($request)
|
||||||
|
{
|
||||||
|
$memberProfile = User::with('detail')->where('nIDUser', $this->nID)->get()->toArray();
|
||||||
|
$dataMemberProfile = [];
|
||||||
|
|
||||||
|
$userInsurance = UserInsurance::where('nIDUser', $this->nID)->get()->first();
|
||||||
|
$memberId = null;
|
||||||
|
$linking = false;
|
||||||
|
|
||||||
|
$jam = date('G'); // Ambil jam dalam format 24 jam
|
||||||
|
|
||||||
|
if ($jam < 12) {
|
||||||
|
$wellcome = "Good Morning!";
|
||||||
|
} elseif ($jam < 18) {
|
||||||
|
$wellcome = "Good Afternoon!";
|
||||||
|
} else {
|
||||||
|
$wellcome = "Good Evening!";
|
||||||
|
}
|
||||||
|
|
||||||
|
if($userInsurance){
|
||||||
|
$memberId = $userInsurance->sNoPolis;
|
||||||
|
$linking = true;
|
||||||
|
} else {
|
||||||
|
$member = Member::where('email', $this->sEmail)->get()->first();
|
||||||
|
$person = Person::where('phone', $this->sPhone)->get()->first();
|
||||||
|
if ($member || $person){ // Autolinking
|
||||||
|
$corporateEmployee = CorporateEmployee::where('member_id', $member->id)->get()->first(); // cek corporate id empolyee/member
|
||||||
|
if ($corporateEmployee){
|
||||||
|
$corporate = Corporate::findOrFail($corporateEmployee->corporate_id)->automatic_linking; // cek autocomplete
|
||||||
|
if ($corporate){
|
||||||
|
if($member) {
|
||||||
|
// Insert into database linksehat
|
||||||
|
$insurance = UserInsurance::updateOrCreate(
|
||||||
|
[
|
||||||
|
'nIDUser' => $this->nID,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'nIDUser' => $this->nID,
|
||||||
|
'nIDInsurance' => $_ENV['LINKSEHAT_ASO_INSURANCE_ID'],
|
||||||
|
'sNoPolis' => $member->member_id,
|
||||||
|
'sNamaPeserta' => $member->fullName,
|
||||||
|
'sKartuPeserta' => '',
|
||||||
|
'sLayanan' => 'RJ,TC',
|
||||||
|
'dStartDate' => $member->members_effective_date,
|
||||||
|
'dExpireDate' => $member->members_expire_date,
|
||||||
|
'dTanggalLahir' => $member->birth_date,
|
||||||
|
'nNoKTP' => $member->nric != '' ? $member->nric : 0 ,
|
||||||
|
'sIsConfrimed' => 1,
|
||||||
|
'sStatus' => 1,
|
||||||
|
]);
|
||||||
|
$message = $member->currentPolicy->corporate->welcome_message;
|
||||||
|
$linking = true;
|
||||||
|
|
||||||
|
$memberId = $member->member_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
'relationship' => $relationship ? $relationship->sHubunganKeluarga : '-',
|
||||||
|
'avatar' => $avatarMember
|
||||||
|
];
|
||||||
|
|
||||||
|
array_push($dataMemberProfile, $dataUser);
|
||||||
|
|
||||||
|
foreach($memberProfile as $m){
|
||||||
|
$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 ? $relationship->sHubunganKeluarga : '-',
|
||||||
|
'avatar' => $avatarMember,
|
||||||
|
];
|
||||||
|
|
||||||
|
array_push( $dataMemberProfile, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$nID = $this->nIDUser ? $this->nIDUser : $this->nID;
|
||||||
|
if ($nID){
|
||||||
|
$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,
|
||||||
|
'relationship' => 'Me',
|
||||||
|
'avatar' => $avatarMember
|
||||||
|
];
|
||||||
|
array_push($dataMemberProfile, $dataUser);
|
||||||
|
|
||||||
|
if (count($memberProfile) > 0){
|
||||||
|
foreach($memberProfile as $m){
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Principal
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Doctor livechat
|
||||||
|
$doctors = Practitioner::with('person', 'practitionerRoles.organization', 'practitionerRoles.speciality')
|
||||||
|
->whereHas('person', function ($query) {
|
||||||
|
$query->where('isOnline', 1); // hanya online
|
||||||
|
})
|
||||||
|
->get()
|
||||||
|
->toArray();
|
||||||
|
$doctorsLivechat = [];
|
||||||
|
foreach($doctors as $doctor){
|
||||||
|
$specialist = 'Umum';
|
||||||
|
$year = 0;
|
||||||
|
$price = 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);
|
||||||
|
$year = $experience->diffInYears(Carbon::now());
|
||||||
|
}
|
||||||
|
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'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data = [
|
||||||
|
'id' => $doctor['id'],
|
||||||
|
'full_name' => $doctor['person']['name'],
|
||||||
|
'specialist' => $specialist,
|
||||||
|
'experience' => $year,
|
||||||
|
'review' => $doctor['person']['review'],
|
||||||
|
'price' => $price,
|
||||||
|
'price_real' => $price
|
||||||
|
];
|
||||||
|
array_push($doctorsLivechat, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hospital List
|
||||||
|
$hospitalList = [];
|
||||||
|
|
||||||
|
$hospitals = Organization::where([
|
||||||
|
'type' => 'hospital',
|
||||||
|
'status' => 'active',
|
||||||
|
])
|
||||||
|
->with('currentAddress')
|
||||||
|
->get()->toArray();
|
||||||
|
foreach($hospitals as $hospital){
|
||||||
|
$lat = 0;
|
||||||
|
$lang = 0;
|
||||||
|
if ($hospital['current_address']['lat']){
|
||||||
|
$lat = $hospital['current_address']['lat'];
|
||||||
|
}
|
||||||
|
if ($hospital['current_address']['lng']){
|
||||||
|
$lang = $hospital['current_address']['lng'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$address = '';
|
||||||
|
if ($hospital['current_address']['text']){
|
||||||
|
$address = $hospital['current_address']['text'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$radius = 0;
|
||||||
|
if ($lat && $lang && $request->longitude && $request->latitude){
|
||||||
|
$radius = round(Helper::calculateDistance($lat, $lang, $request->latitude, $request->longitude), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name' => $hospital['name'],
|
||||||
|
'radius' => $radius,
|
||||||
|
'image' => '',
|
||||||
|
'address' => $address
|
||||||
|
];
|
||||||
|
|
||||||
|
array_push($hospitalList, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
usort($hospitalList, function($a, $b) {
|
||||||
|
return $a['radius'] <=> $b['radius'];
|
||||||
|
});
|
||||||
|
|
||||||
|
$hospitalList = array_slice($hospitalList, 0, 5);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => $this->nID,
|
||||||
|
'message' => $wellcome,
|
||||||
|
'full_name' => $this->sFirstName . ' '. $this->sLastName,
|
||||||
|
'avatar' => $avatar,
|
||||||
|
'member_id' => $memberId,
|
||||||
|
'linking' => $linking,
|
||||||
|
'doctors_livechat' => $doctorsLivechat,
|
||||||
|
'hospital' => $hospitalList
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
85
Modules/Linksehat/Transformers/Livechat/LivechatResource.php
Normal file
85
Modules/Linksehat/Transformers/Livechat/LivechatResource.php
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Linksehat\Transformers\Livechat;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
use App\Models\Practitioner;
|
||||||
|
use App\Models\PractitionerRole;
|
||||||
|
use App\Models\Speciality;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use DB;
|
||||||
|
|
||||||
|
|
||||||
|
class LivechatResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
protected $connection = 'oldlms';
|
||||||
|
|
||||||
|
public function __construct($resource, $request)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
parent::__construct($resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray($request)
|
||||||
|
{
|
||||||
|
// Specialis
|
||||||
|
$specialists = Speciality::all();
|
||||||
|
|
||||||
|
// Doctor livechat
|
||||||
|
$doctors = Practitioner::with('person', 'practitionerRoles.organization', 'practitionerRoles.speciality')
|
||||||
|
->whereHas('person', function ($query) {
|
||||||
|
$query->where('isOnline', 1); // hanya online
|
||||||
|
})
|
||||||
|
->get()
|
||||||
|
->toArray();
|
||||||
|
$doctorsLivechat = [];
|
||||||
|
foreach($doctors as $doctor){
|
||||||
|
$specialist = 'Umum';
|
||||||
|
$year = 0;
|
||||||
|
$price = 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);
|
||||||
|
$year = $experience->diffInYears(Carbon::now());
|
||||||
|
}
|
||||||
|
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'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data = [
|
||||||
|
'id' => $doctor['id'],
|
||||||
|
'full_name' => $doctor['person']['name'],
|
||||||
|
'specialist' => $specialist,
|
||||||
|
'experience' => $year,
|
||||||
|
'review' => $doctor['person']['review'],
|
||||||
|
'price' => $price,
|
||||||
|
'price_real' => $price
|
||||||
|
];
|
||||||
|
array_push($doctorsLivechat, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'jadwal_weekday' => 'Senin - Jumat (08:00 - 17:30)',
|
||||||
|
'jadwal_weekend' => 'Sabtu (08:00 - 12:00)',
|
||||||
|
'doctors_livechat' =>
|
||||||
|
$doctorsLivechat
|
||||||
|
,
|
||||||
|
'specialist' => $specialists
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
44
app/Events/ChatMessageSent.php
Normal file
44
app/Events/ChatMessageSent.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use Illuminate\Broadcasting\Channel;
|
||||||
|
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||||
|
use Illuminate\Broadcasting\PresenceChannel;
|
||||||
|
use Illuminate\Broadcasting\PrivateChannel;
|
||||||
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||||
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class ChatMessageSent implements ShouldBroadcast
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
public $message;
|
||||||
|
public function __construct($message)
|
||||||
|
{
|
||||||
|
$this->message = $message;
|
||||||
|
$this->dontBroadcastToCurrentUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the channels the event should broadcast on.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Broadcasting\Channel|array
|
||||||
|
*/
|
||||||
|
public function broadcastOn()
|
||||||
|
{
|
||||||
|
return new PrivateChannel('chat.' . $this->message->channel_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function broadcastAs(): string
|
||||||
|
{
|
||||||
|
return 'chat.sent';
|
||||||
|
}
|
||||||
|
}
|
||||||
167
app/Helpers/DuitkuHelper.php
Normal file
167
app/Helpers/DuitkuHelper.php
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Helpers;
|
||||||
|
|
||||||
|
class DuitkuHelper
|
||||||
|
{
|
||||||
|
public static function configuration()
|
||||||
|
{
|
||||||
|
$duitkuConfig = new \Duitku\Config(env('API_KEY_DUITKU'), env('CODE_MERCHANT_DUITKU'));
|
||||||
|
// false for production mode
|
||||||
|
// true for sandbox mode
|
||||||
|
$duitkuConfig->setSandboxMode(true);
|
||||||
|
// set sanitizer (default : true)
|
||||||
|
$duitkuConfig->setSanitizedMode(false);
|
||||||
|
// set log parameter (default : true)
|
||||||
|
$duitkuConfig->setDuitkuLogs(false);
|
||||||
|
return $duitkuConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function paymentMethod()
|
||||||
|
{
|
||||||
|
$duitkuConfig = self::configuration();
|
||||||
|
try {
|
||||||
|
$paymentAmount = "10000"; //"YOUR_AMOUNT";
|
||||||
|
$paymentMethodList = \Duitku\Pop::getPaymentMethod($paymentAmount, $duitkuConfig);
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
return $paymentMethodList;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function checkStatus($merchantOrderId)
|
||||||
|
{
|
||||||
|
$duitkuConfig = self::configuration();
|
||||||
|
$data = [
|
||||||
|
'merchantOrderId' => $merchantOrderId
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
$transactionList = \Duitku\Pop::transactionStatus($merchantOrderId, $duitkuConfig);
|
||||||
|
|
||||||
|
$transaction = json_decode($transactionList);
|
||||||
|
|
||||||
|
if ($transaction->statusCode == "00" || $transaction->statusCode == "01") {
|
||||||
|
// Transaksi berhasil atau dalam proses
|
||||||
|
return $transaction;
|
||||||
|
} else {
|
||||||
|
// Transaksi gagal atau kedaluwarsa
|
||||||
|
return ['error' => true];
|
||||||
|
}
|
||||||
|
} catch (\Duitku\Exceptions\DuitkuException $e) {
|
||||||
|
// Tangani pengecualian yang terkait dengan Duitku
|
||||||
|
return ['error' => true, 'message' => $e->getMessage()];
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Tangani pengecualian umum
|
||||||
|
return ['error' => true, 'message' => $e->getMessage()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createInvoice($data)
|
||||||
|
{
|
||||||
|
#CONTOH DARI DUITKU
|
||||||
|
// $paymentMethod = ""; // PaymentMethod list => https://docs.duitku.com/pop/id/#payment-method
|
||||||
|
// $paymentAmount = 10000; // Amount
|
||||||
|
// $email = "customer@gmail.com"; // your customer email
|
||||||
|
// $phoneNumber = "081234567890"; // your customer phone number (optional)
|
||||||
|
// $productDetails = "Test Payment";
|
||||||
|
// $merchantOrderId = "2"; // from merchant, unique
|
||||||
|
// $additionalParam = ''; // optional
|
||||||
|
// $merchantUserInfo = ''; // optional
|
||||||
|
// $customerVaName = 'John Doe'; // display name on bank confirmation display
|
||||||
|
// $callbackUrl = 'http://YOUR_SERVER/callback'; // url for callback
|
||||||
|
// $returnUrl = 'http://YOUR_SERVER/return'; // url for redirect
|
||||||
|
// $expiryPeriod = 60; // set the expired time in minutes
|
||||||
|
|
||||||
|
// // Customer Detail
|
||||||
|
// $firstName = "John";
|
||||||
|
// $lastName = "Doe";
|
||||||
|
|
||||||
|
// // Address
|
||||||
|
// $alamat = "Jl. Kembangan Raya";
|
||||||
|
// $city = "Jakarta";
|
||||||
|
// $postalCode = "11530";
|
||||||
|
// $countryCode = "ID";
|
||||||
|
|
||||||
|
$paymentMethod = $data['paymentMethod']; // PaymentMethod list => https://docs.duitku.com/pop/id/#payment-method
|
||||||
|
$paymentAmount = $data['paymentAmount']; // Amount
|
||||||
|
$email = $data['email']; // your customer email
|
||||||
|
$phoneNumber = $data['phoneNumber']; // your customer phone number (optional)
|
||||||
|
$productDetails = $data['productDetails'];
|
||||||
|
$merchantOrderId = $data['merchantOrderId']; // from merchant, unique
|
||||||
|
$additionalParam = $data['additionalParam']; // optional
|
||||||
|
$merchantUserInfo = $data['merchantUserInfo']; // optional
|
||||||
|
$customerVaName = $data['customerVaName']; // display name on bank confirmation display
|
||||||
|
$callbackUrl = env('DUITKU_PAYMENT_CALLBACK_URL'); // url for callback
|
||||||
|
$returnUrl = env('APP_URL').'/api/linksehat/redirect-duitku';; // url for redirect
|
||||||
|
$expiryPeriod = 60; // set the expired time in minutes
|
||||||
|
|
||||||
|
// Customer Detail
|
||||||
|
$firstName = $data['firstName'];
|
||||||
|
$lastName = $data['lastName'];
|
||||||
|
|
||||||
|
// Address
|
||||||
|
$alamat = $data['alamat'];
|
||||||
|
$city = $data['city'];
|
||||||
|
$postalCode = $data['postalCode'];
|
||||||
|
$countryCode = "ID";
|
||||||
|
|
||||||
|
$address = array(
|
||||||
|
'firstName' => $firstName,
|
||||||
|
'lastName' => $lastName,
|
||||||
|
'address' => $alamat,
|
||||||
|
'city' => $city,
|
||||||
|
'postalCode' => $postalCode,
|
||||||
|
'phone' => $phoneNumber,
|
||||||
|
'countryCode' => $countryCode
|
||||||
|
);
|
||||||
|
|
||||||
|
$customerDetail = array(
|
||||||
|
'firstName' => $firstName,
|
||||||
|
'lastName' => $lastName,
|
||||||
|
'email' => $email,
|
||||||
|
'phoneNumber' => $phoneNumber,
|
||||||
|
'billingAddress' => $address,
|
||||||
|
'shippingAddress' => $address
|
||||||
|
);
|
||||||
|
|
||||||
|
// Item Details
|
||||||
|
$item1 = array(
|
||||||
|
'name' => $productDetails,
|
||||||
|
'price' => $paymentAmount,
|
||||||
|
'quantity' => 1
|
||||||
|
);
|
||||||
|
|
||||||
|
$itemDetails = array(
|
||||||
|
$item1
|
||||||
|
);
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'paymentAmount' => $paymentAmount,
|
||||||
|
'merchantOrderId' => $merchantOrderId,
|
||||||
|
'productDetails' => $productDetails,
|
||||||
|
'additionalParam' => $additionalParam,
|
||||||
|
'merchantUserInfo' => $merchantUserInfo,
|
||||||
|
'customerVaName' => $customerVaName,
|
||||||
|
'email' => $email,
|
||||||
|
'phoneNumber' => $phoneNumber,
|
||||||
|
'itemDetails' => $itemDetails,
|
||||||
|
'customerDetail' => $customerDetail,
|
||||||
|
'callbackUrl' => $callbackUrl,
|
||||||
|
'returnUrl' => $returnUrl,
|
||||||
|
'expiryPeriod' => $expiryPeriod
|
||||||
|
);
|
||||||
|
$duitkuConfig = self::configuration();
|
||||||
|
try {
|
||||||
|
// createInvoice Request
|
||||||
|
$responseDuitkuPop = \Duitku\Pop::createInvoice($params, $duitkuConfig);
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
return json_decode($responseDuitkuPop);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return json_decode($e->getMessage());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ use Illuminate\Support\Facades\DB;
|
|||||||
use App\Models\Member;
|
use App\Models\Member;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
|
use App\Models\Icd;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
|
|
||||||
class Helper
|
class Helper
|
||||||
@@ -117,6 +118,16 @@ class Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function diagnosisName($code)
|
||||||
|
{
|
||||||
|
$icd = Icd::where('code', $code)->get()->first();
|
||||||
|
if ($icd){
|
||||||
|
return $icd->name;
|
||||||
|
} else {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function paginateResources($resource)
|
public static function paginateResources($resource)
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@@ -258,11 +269,14 @@ class Helper
|
|||||||
*
|
*
|
||||||
* @param array|object $data
|
* @param array|object $data
|
||||||
* @param int $statusCode
|
* @param int $statusCode
|
||||||
* @param string $message
|
* @param string|array|object $message
|
||||||
* @return JsonResponse
|
* @return JsonResponse
|
||||||
*/
|
*/
|
||||||
public static function responseJson(array|object $data = [], string $status = 'success', int $statusCode = Response::HTTP_OK, string $message = 'Data berhasil di ambil'): JsonResponse
|
public static function responseJson(array|object $data = [], string $status = 'success', int $statusCode = Response::HTTP_OK, string|array|object $message = 'Data berhasil di ambil'): JsonResponse
|
||||||
{
|
{
|
||||||
|
if ($message instanceof \Illuminate\Support\MessageBag) {
|
||||||
|
$message = $message->first();
|
||||||
|
}
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
'statusCode' => $statusCode,
|
'statusCode' => $statusCode,
|
||||||
@@ -377,9 +391,7 @@ class Helper
|
|||||||
$mail->send();
|
$mail->send();
|
||||||
return true;
|
return true;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
dd($e);
|
return $mail->ErrorInfo;
|
||||||
return ($mail->ErrorInfo);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,4 +455,48 @@ class Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function calculateDistance($latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371) {
|
||||||
|
// Convert degrees to radians
|
||||||
|
$latFrom = deg2rad($latitudeFrom);
|
||||||
|
$lonFrom = deg2rad($longitudeFrom);
|
||||||
|
$latTo = deg2rad($latitudeTo);
|
||||||
|
$lonTo = deg2rad($longitudeTo);
|
||||||
|
|
||||||
|
// Calculate the change in coordinates
|
||||||
|
$deltaLat = $latTo - $latFrom;
|
||||||
|
$deltaLon = $lonTo - $lonFrom;
|
||||||
|
|
||||||
|
// Apply Haversine formula
|
||||||
|
$a = sin($deltaLat / 2) * sin($deltaLat / 2) + cos($latFrom) * cos($latTo) * sin($deltaLon / 2) * sin($deltaLon / 2);
|
||||||
|
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
|
||||||
|
$distance = $earthRadius * $c;
|
||||||
|
|
||||||
|
return $distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function calculateAge($date_brith_day){
|
||||||
|
// Konversi tanggal lahir ke dalam format UNIX timestamp
|
||||||
|
$dob = strtotime($date_brith_day);
|
||||||
|
|
||||||
|
// Hitung umur berdasarkan tanggal lahir
|
||||||
|
$umur = date('Y') - date('Y', $dob);
|
||||||
|
|
||||||
|
// Periksa apakah ulang tahun sudah lewat atau belum
|
||||||
|
if (date('md', $dob) > date('md')) {
|
||||||
|
$umur--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mengembalikan umur dalam format "x years old"
|
||||||
|
return $umur . ' years old';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function calculateDateDifference($startDate, $endDate)
|
||||||
|
{
|
||||||
|
$start = Carbon::parse($startDate);
|
||||||
|
$end = Carbon::parse($endDate);
|
||||||
|
|
||||||
|
return $start->diffInDays($end) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ namespace App\Http\Resources\OLDLMS;
|
|||||||
|
|
||||||
use App\Services\ClaimService;
|
use App\Services\ClaimService;
|
||||||
use App\Models\Corporate;
|
use App\Models\Corporate;
|
||||||
|
use App\Models\CorporateBenefit;
|
||||||
|
use App\Models\RequestLog;
|
||||||
|
use App\Models\RequestLogBenefit;
|
||||||
|
use App\Models\MemberPlan;
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
|
||||||
@@ -21,6 +27,45 @@ class MemberResource extends JsonResource
|
|||||||
$currentMemberPlan = $this->memberPlans?->first();
|
$currentMemberPlan = $this->memberPlans?->first();
|
||||||
$limitTelecon = $currentMemberPlan->plan->limit_telecon ?? null;
|
$limitTelecon = $currentMemberPlan->plan->limit_telecon ?? null;
|
||||||
$limitTelecon = $this->totalUsage >= 6 ? null : $limitTelecon;
|
$limitTelecon = $this->totalUsage >= 6 ? null : $limitTelecon;
|
||||||
|
$services = MemberPlan::where('member_id', $this->id)->with('plan')->get()->toArray();
|
||||||
|
$dataServices = [];
|
||||||
|
if ($services) {
|
||||||
|
foreach($services as $service) {
|
||||||
|
$serviceName = Helper::serviceName($service['plan']['service_code']);
|
||||||
|
$benefits = CorporateBenefit::where('plan_id', $service['plan_id'])->with('benefit')->get()->toArray();
|
||||||
|
$dataBenefit = [];
|
||||||
|
foreach($benefits as $benefit){
|
||||||
|
$dataBenefitItem = $benefit['benefit']['description'];
|
||||||
|
array_push($dataBenefit, $dataBenefitItem);
|
||||||
|
}
|
||||||
|
$data = [
|
||||||
|
'name' => $serviceName,
|
||||||
|
'benefit' => $dataBenefit
|
||||||
|
];
|
||||||
|
|
||||||
|
array_push($dataServices, $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG
|
||||||
|
$dataLog = [];
|
||||||
|
$requestLogs = RequestLog::where('member_id', $this->id)->with('organization')->get()->toArray();
|
||||||
|
$totalBenefit = 0;
|
||||||
|
if ($requestLogs) {
|
||||||
|
foreach($requestLogs as $requestLog) {
|
||||||
|
$requestLogBenefit = RequestLogBenefit::where('request_log_id', $requestLog['id'])->sum('amount_approved');
|
||||||
|
$totalBenefit += $requestLogBenefit;
|
||||||
|
$data = [
|
||||||
|
'id' => $requestLog['id'],
|
||||||
|
'code' => $requestLog['code'],
|
||||||
|
'submission_date' => Carbon::parse($requestLog['submission_date'])->format('d M Y H:i:s'),
|
||||||
|
'provider_name' => $requestLog['organization']['name'],
|
||||||
|
'service' => Helper::serviceName($requestLog['service_code'])
|
||||||
|
];
|
||||||
|
|
||||||
|
array_push($dataLog, $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
@@ -33,6 +78,9 @@ class MemberResource extends JsonResource
|
|||||||
'start_date' => $this->members_effective_date,
|
'start_date' => $this->members_effective_date,
|
||||||
'corporate_logo' => $_ENV['LMS_APP_STORAGE'] . $this->corporateLogo,
|
'corporate_logo' => $_ENV['LMS_APP_STORAGE'] . $this->corporateLogo,
|
||||||
'valid_until' => $this->members_expire_date,
|
'valid_until' => $this->members_expire_date,
|
||||||
|
'total_benefit_usage' => $totalBenefit,
|
||||||
|
'service' => $dataServices,
|
||||||
|
'histor_log' => $dataLog
|
||||||
|
|
||||||
];
|
];
|
||||||
return $data;
|
return $data;
|
||||||
|
|||||||
32
app/Listeners/ProcessChatMessage.php
Normal file
32
app/Listeners/ProcessChatMessage.php
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Listeners;
|
||||||
|
|
||||||
|
use App\Events\ChatMessageSent;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
|
||||||
|
class ProcessChatMessage
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param object $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle(ChatMessageSent $event)
|
||||||
|
{
|
||||||
|
// Proses pesan yang diterima dari event
|
||||||
|
$message = $event->message;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
app/Models/Channel.php
Normal file
17
app/Models/Channel.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Channel extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'type',
|
||||||
|
'member_id',
|
||||||
|
'doctor_id',
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -52,6 +52,7 @@ class File extends Model
|
|||||||
'final-log-kondisi' => 'final-log/',
|
'final-log-kondisi' => 'final-log/',
|
||||||
'docs' => 'docs/',
|
'docs' => 'docs/',
|
||||||
'additional-files' => 'additional-files/',
|
'additional-files' => 'additional-files/',
|
||||||
|
'chat' => 'chat/',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function fileable()
|
public function fileable()
|
||||||
@@ -89,4 +90,15 @@ class File extends Model
|
|||||||
$file->storeAs('public/' . $directory, $fileName . '.' . $extension);
|
$file->storeAs('public/' . $directory, $fileName . '.' . $extension);
|
||||||
return $path;
|
return $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function storeFileChat($type, $id, $file)
|
||||||
|
{
|
||||||
|
// $fileName = self::getFileName($type, $id);
|
||||||
|
$fileName = $file->getClientOriginalName();
|
||||||
|
$directory = self::getDirectory($type);
|
||||||
|
$extension = $file->getClientOriginalExtension();
|
||||||
|
$path = $directory . $fileName . '.' . $extension;
|
||||||
|
$file->store('public/' .$path);
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
44
app/Models/Livechat.php
Normal file
44
app/Models/Livechat.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Traits\Blameable;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class Livechat extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes, Blameable;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'uuid',
|
||||||
|
'doctor_id',
|
||||||
|
'patient_id',
|
||||||
|
'organization_id',
|
||||||
|
'timezone',
|
||||||
|
'descriptions',
|
||||||
|
'payment_method',
|
||||||
|
'request_date',
|
||||||
|
'accept_date',
|
||||||
|
'start_date',
|
||||||
|
'end_date',
|
||||||
|
'status',
|
||||||
|
'subject',
|
||||||
|
'object',
|
||||||
|
'assessment',
|
||||||
|
'plan',
|
||||||
|
'health_certificate_start',
|
||||||
|
'health_certificate_end',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function doctor() {
|
||||||
|
return $this->belongsTo(Person::class, 'doctor_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function practitioner() {
|
||||||
|
return $this->belongsTo(Practitioner::class, 'doctor_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
25
app/Models/Message.php
Normal file
25
app/Models/Message.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Message extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
protected $connection = 'mysql';
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'channel_id',
|
||||||
|
'content',
|
||||||
|
'type',
|
||||||
|
'from_user'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function files()
|
||||||
|
{
|
||||||
|
return $this->morphMany(File::class, 'fileable')->whereNull('deleted_at');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -70,4 +70,8 @@ class Livechat extends Model
|
|||||||
{
|
{
|
||||||
return $this->belongsTo(Healthcare::class, 'nIDHealthCare', 'nID');
|
return $this->belongsTo(Healthcare::class, 'nIDHealthCare', 'nID');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function summary(){
|
||||||
|
return $this->belongsTo(LivechatSummary::class, 'nID', 'nIDLivechat');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
40
app/Models/OLDLMS/LivechatSummary.php
Normal file
40
app/Models/OLDLMS/LivechatSummary.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\OLDLMS;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class LivechatSummary extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
|
||||||
|
// public $sStatusNames = [
|
||||||
|
// 0 => 'Menunggu Konfirmasi',
|
||||||
|
// 1 => 'Diterima',
|
||||||
|
// 3 => 'Ditolak',
|
||||||
|
// 2 => 'Selesai',
|
||||||
|
// 4 => 'Expired',
|
||||||
|
// ];
|
||||||
|
|
||||||
|
public $sStatusNames = [
|
||||||
|
0 => 'Request TC',
|
||||||
|
1 => 'Accepted by Doctor but User not Payment',
|
||||||
|
3 => 'Decline by Doctor',
|
||||||
|
2 => 'Payment Success',
|
||||||
|
4 => 'Payment Expired',
|
||||||
|
5 => 'Cancel by Patient'
|
||||||
|
];
|
||||||
|
|
||||||
|
const CREATED_AT = 'dCreateOn';
|
||||||
|
const UPDATED_AT = 'dUpdateOn';
|
||||||
|
const DELETED_AT = 'dDeleteOn';
|
||||||
|
|
||||||
|
protected $connection = 'oldlms';
|
||||||
|
|
||||||
|
protected $table = 'tx_livechat_summary';
|
||||||
|
|
||||||
|
protected $primaryKey = 'nID';
|
||||||
|
}
|
||||||
@@ -10,6 +10,20 @@ class Prescription extends Model
|
|||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'nIDLivechat',
|
||||||
|
'nIDLivechatSummary',
|
||||||
|
'nIDDokter',
|
||||||
|
'sDokterName',
|
||||||
|
'dTanggalResep',
|
||||||
|
'sSource',
|
||||||
|
'nIDUser',
|
||||||
|
'sRegID',
|
||||||
|
'sKodeResep',
|
||||||
|
'sDiagnose',
|
||||||
|
'sKodeRS',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
// public $sStatusNames = [
|
// public $sStatusNames = [
|
||||||
// 0 => 'Menunggu Konfirmasi',
|
// 0 => 'Menunggu Konfirmasi',
|
||||||
@@ -27,6 +41,8 @@ class Prescription extends Model
|
|||||||
|
|
||||||
protected $table = 'tx_prescriptions';
|
protected $table = 'tx_prescriptions';
|
||||||
|
|
||||||
|
protected $primaryKey = 'nID';
|
||||||
|
|
||||||
// protected $appends = [
|
// protected $appends = [
|
||||||
// 'status_name',
|
// 'status_name',
|
||||||
// ];
|
// ];
|
||||||
|
|||||||
52
app/Models/OLDLMS/PrescriptionItem.php
Normal file
52
app/Models/OLDLMS/PrescriptionItem.php
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\OLDLMS;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PrescriptionItem extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'nIDPrescription',
|
||||||
|
'sItemCode',
|
||||||
|
'sOriginCode',
|
||||||
|
'sItemName',
|
||||||
|
'nQty',
|
||||||
|
'sSatuan',
|
||||||
|
'sSigna',
|
||||||
|
'sNote',
|
||||||
|
'isRacikan',
|
||||||
|
'ParentCode',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
// public $sStatusNames = [
|
||||||
|
// 0 => 'Menunggu Konfirmasi',
|
||||||
|
// 1 => 'Diterima',
|
||||||
|
// 2 => 'Ditolak',
|
||||||
|
// 3 => 'Selesai',
|
||||||
|
// 4 => 'Expired',
|
||||||
|
// ];
|
||||||
|
|
||||||
|
const CREATED_AT = 'dCreateOn';
|
||||||
|
const UPDATED_AT = 'dUpdateOn';
|
||||||
|
const DELETED_AT = 'dDeleteOn';
|
||||||
|
|
||||||
|
protected $connection = 'oldlms';
|
||||||
|
|
||||||
|
protected $table = 'tx_prescription_items';
|
||||||
|
|
||||||
|
// protected $appends = [
|
||||||
|
// 'status_name',
|
||||||
|
// ];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'dTanggalResep' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $primaryKey = 'nID';
|
||||||
|
}
|
||||||
@@ -38,6 +38,7 @@ class User extends Authenticatable
|
|||||||
'sEmail',
|
'sEmail',
|
||||||
'nIDHubunganKeluarga',
|
'nIDHubunganKeluarga',
|
||||||
'dUpdateOn',
|
'dUpdateOn',
|
||||||
|
'sIPAddress',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected function fullName(): Attribute
|
protected function fullName(): Attribute
|
||||||
|
|||||||
20
app/Models/PaymentsMethods.php
Normal file
20
app/Models/PaymentsMethods.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PaymentsMethods extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
protected $table = 'payment_methods';
|
||||||
|
protected $fillable = [
|
||||||
|
'config_pmc_id',
|
||||||
|
'code',
|
||||||
|
'name',
|
||||||
|
'image',
|
||||||
|
'timeout',
|
||||||
|
'active'
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -23,6 +23,8 @@ class Person extends Model
|
|||||||
'birth_date',
|
'birth_date',
|
||||||
'birth_place',
|
'birth_place',
|
||||||
'language',
|
'language',
|
||||||
|
'isOnline',
|
||||||
|
'review',
|
||||||
'race',
|
'race',
|
||||||
'citizenship',
|
'citizenship',
|
||||||
'current_employment',
|
'current_employment',
|
||||||
|
|||||||
18
app/Models/Prescription.php
Normal file
18
app/Models/Prescription.php
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Traits\Blameable;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class Prescription extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
protected $fillable = [
|
||||||
|
'livechat_id',
|
||||||
|
'organization_id',
|
||||||
|
'icd_code'
|
||||||
|
];
|
||||||
|
}
|
||||||
20
app/Models/PrescriptionItem.php
Normal file
20
app/Models/PrescriptionItem.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PrescriptionItem extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
protected $fillable = [
|
||||||
|
'prescription_id',
|
||||||
|
'drug_id',
|
||||||
|
'qty',
|
||||||
|
'unit_id',
|
||||||
|
'note',
|
||||||
|
'signa',
|
||||||
|
'direction'
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -20,6 +20,8 @@ class RequestLog extends Model
|
|||||||
|
|
||||||
public $fillable = [
|
public $fillable = [
|
||||||
'uuid',
|
'uuid',
|
||||||
|
'invoice_no',
|
||||||
|
'billing_no',
|
||||||
'submission_date',
|
'submission_date',
|
||||||
'discharge_date',
|
'discharge_date',
|
||||||
'member_id',
|
'member_id',
|
||||||
|
|||||||
17
app/Models/UserChannel.php
Normal file
17
app/Models/UserChannel.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class UserChannel extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
protected $connection = 'mysql';
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'channel_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ namespace App\Providers;
|
|||||||
use App\Events\ClaimApproved;
|
use App\Events\ClaimApproved;
|
||||||
use App\Listeners\LogClaimJournal;
|
use App\Listeners\LogClaimJournal;
|
||||||
use App\Listeners\NotifyClaimRequested;
|
use App\Listeners\NotifyClaimRequested;
|
||||||
|
use App\Listeners\ProcessChatMessage;
|
||||||
use Illuminate\Auth\Events\Registered;
|
use Illuminate\Auth\Events\Registered;
|
||||||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||||
@@ -30,6 +31,10 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
LogClaimJournal::class,
|
LogClaimJournal::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
ChatMessageSent::class => [
|
||||||
|
ProcessChatMessage::class,
|
||||||
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class Duitku
|
|||||||
$merchantUserInfo = ''; // optional
|
$merchantUserInfo = ''; // optional
|
||||||
$customerVaName = $patient->name ?? ''; // display name on bank confirmation display
|
$customerVaName = $patient->name ?? ''; // display name on bank confirmation display
|
||||||
$callbackUrl = env('DUITKU_PAYMENT_CALLBACK_URL'); // url for callback
|
$callbackUrl = env('DUITKU_PAYMENT_CALLBACK_URL'); // url for callback
|
||||||
$returnUrl = 'https://dev-superapp.primaya.id';
|
$returnUrl = env('');
|
||||||
$expiryPeriod = $paymentMethods->timeout; // set the expired time in minutes
|
$expiryPeriod = $paymentMethods->timeout; // set the expired time in minutes
|
||||||
|
|
||||||
// Customer Detail
|
// Customer Detail
|
||||||
@@ -53,9 +53,9 @@ class Duitku
|
|||||||
$lastName = $patient->last_name ?? '';
|
$lastName = $patient->last_name ?? '';
|
||||||
|
|
||||||
// Address
|
// Address
|
||||||
$alamat = $patient->address->first()->line ?? '';
|
$alamat = $patient->address?? '';
|
||||||
// dd($alamat);
|
// dd($alamat);
|
||||||
$city = $patient->address->first()->city->name ?? '';
|
$city = $patient->city ?? '';
|
||||||
// dd($city);
|
// dd($city);
|
||||||
$postalCode = $patient->postal_code ?? '';
|
$postalCode = $patient->postal_code ?? '';
|
||||||
$countryCode = "ID";
|
$countryCode = "ID";
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ return [
|
|||||||
'port' => env('PUSHER_PORT', 443),
|
'port' => env('PUSHER_PORT', 443),
|
||||||
'scheme' => env('PUSHER_SCHEME', 'https'),
|
'scheme' => env('PUSHER_SCHEME', 'https'),
|
||||||
'encrypted' => true,
|
'encrypted' => true,
|
||||||
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
'cluster' => 'ap1',
|
||||||
|
'useTLS' => true
|
||||||
|
|
||||||
],
|
],
|
||||||
'client_options' => [
|
'client_options' => [
|
||||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
||||||
|
|||||||
@@ -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('benefits', function (Blueprint $table) {
|
||||||
|
$table->integer('type')->nullable()->default(1)->comment('1=Non COB, 2=Cob');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('benefits', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('type');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?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('persons', function (Blueprint $table) {
|
||||||
|
$table->dateTime('start_date_work')->nullable()->after('birth_place');
|
||||||
|
$table->integer('isOnline')
|
||||||
|
->default(0)
|
||||||
|
->comment('0=offline, 1=online')
|
||||||
|
->after('start_date_work');
|
||||||
|
$table->double('review')->after('isOnline');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('persons', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('start_date_work');
|
||||||
|
$table->dropColumn('isOnline');
|
||||||
|
$table->dropColumn('review');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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('practitioner_roles', function (Blueprint $table) {
|
||||||
|
$table->integer('price')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('practitioner_roles', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('price');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?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('livechats', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('doctor_id');
|
||||||
|
$table->foreignId('patient_id');
|
||||||
|
$table->foreignId('organization_id');
|
||||||
|
$table->string('timezone')->nullable()->default(null);
|
||||||
|
$table->text('descriptions');
|
||||||
|
$table->string('payment_method');
|
||||||
|
$table->dateTime('request_date')->nullable();
|
||||||
|
$table->dateTime('accept_date')->nullable();
|
||||||
|
$table->dateTime('start_date')->nullable();
|
||||||
|
$table->dateTime('end_date')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
$table->softDeletes();
|
||||||
|
|
||||||
|
$table->foreignId('created_by')->nullable();
|
||||||
|
$table->foreignId('updated_by')->nullable();
|
||||||
|
$table->foreignId('deleted_by')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('livechats');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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('livechats', function (Blueprint $table) {
|
||||||
|
$table->string('uuid')->after('id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('livechats', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('uuid');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?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('person_educations', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->bigInteger('person_id');
|
||||||
|
$table->integer('level_id')->comment('1=SD, 2= SMP, 3=SMA dst.');
|
||||||
|
$table->string('name', 255);
|
||||||
|
$table->dateTime('start_date');
|
||||||
|
$table->dateTime('end_date');
|
||||||
|
$table->bigInteger('created_by')->nullable();
|
||||||
|
$table->bigInteger('updated_by')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('person_educations');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?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('practitioners', function (Blueprint $table) {
|
||||||
|
$table->string('str_number', 255)->after('person_id')->nullable();
|
||||||
|
$table->dateTime('exp_date_str')->after('str_number')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('practitioners', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('str_number');
|
||||||
|
$table->dropColumn('exp_date_str');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?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('practitioner_roles', function (Blueprint $table) {
|
||||||
|
$table->string('sip_number', 255)->after('period_end')->nullable();
|
||||||
|
$table->dateTime('exp_date_sip')->after('sip_number')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('practitioner_roles', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('sip_number');
|
||||||
|
$table->dropColumn('exp_date_sip');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?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('request_logs', function (Blueprint $table) {
|
||||||
|
$table->string('invoice_no')->after('code')->nullable();
|
||||||
|
$table->string('billing_no')->after('invoice_no')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('request_logs', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('invoice_no');
|
||||||
|
$table->dropColumn('billing_no');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?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('prescriptions', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('livechat_id');
|
||||||
|
$table->foreignId('organization_id');
|
||||||
|
$table->string('icd_code');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('prescriptions');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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('prescription_items', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('prescription_id');
|
||||||
|
$table->foreignId('drug_id');
|
||||||
|
$table->integer('qty');
|
||||||
|
$table->foreignId('unit_id');
|
||||||
|
$table->string('note');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('prescription_items');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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('prescription_items', function (Blueprint $table) {
|
||||||
|
$table->string('signa');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('prescription_items', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('signa');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?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('user_channels', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->timestamps();
|
||||||
|
$table->foreignId('user_id');
|
||||||
|
$table->foreignId('channel_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('user_channels');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?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('channels', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->timestamps();
|
||||||
|
$table->string('name');
|
||||||
|
$table->string('type');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('channels');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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('messages', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->timestamps();
|
||||||
|
$table->foreignId('from_user');
|
||||||
|
$table->foreignId('channel_id');
|
||||||
|
$table->text('content');
|
||||||
|
$table->string('type');
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('messages');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?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('channels', function (Blueprint $table) {
|
||||||
|
$table->foreignId('member_id');
|
||||||
|
$table->foreignId('doctor_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('channels', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('member_id');
|
||||||
|
$table->dropColumn('doctor_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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('drugs', function (Blueprint $table) {
|
||||||
|
$table->decimal('price', 8, 2)->nullable()->after('active');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('drugs', function (Blueprint $table) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('livechats', function (Blueprint $table) {
|
||||||
|
$table->integer('status')->after('end_date')->comment('1=Request, 2=Accept, 3=Decline, 4=Waiting Payment, 5=Success Payment, 6 = End Chat');
|
||||||
|
$table->string('subject')->after('status')->nullable();
|
||||||
|
$table->string('object')->after('subject')->nullable();
|
||||||
|
$table->string('assessment')->after('object')->nullable();
|
||||||
|
$table->text('plan')->after('assessment')->nullable();
|
||||||
|
$table->date('health_certificate_start')->after('end_date')->nullable();
|
||||||
|
$table->date('health_certificate_end')->after('health_certificate_start')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('livechats', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('status');
|
||||||
|
$table->dropColumn('subject');
|
||||||
|
$table->dropColumn('object');
|
||||||
|
$table->dropColumn('assessment');
|
||||||
|
$table->dropColumn('plan');
|
||||||
|
$table->dropColumn('health_certificate_start');
|
||||||
|
$table->dropColumn('health_certificate_end');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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('prescription_items', function (Blueprint $table) {
|
||||||
|
$table->string('direction')->after('signa')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('prescription_items', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('direction');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
208
frontend/client-portal/src/components/DialogUpdateStatus.tsx
Normal file
208
frontend/client-portal/src/components/DialogUpdateStatus.tsx
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
import * as Yup from 'yup';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { Dialog, DialogTitle, DialogContent, Stack, Typography, IconButton, Grid } from '@mui/material';
|
||||||
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
|
import { ReactElement } from 'react';
|
||||||
|
import Iconify from './Iconify';
|
||||||
|
import { Card } from '@mui/material';
|
||||||
|
import { FormProvider, RHFTextField, RHFSwitch, RHFSelect } from './hook-form';
|
||||||
|
import { Button } from '@mui/material';
|
||||||
|
import { LoadingButton } from '@mui/lab';
|
||||||
|
import axios from '@/utils/axios';
|
||||||
|
import { enqueueSnackbar } from 'notistack';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type DataContent = {
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
id: number;
|
||||||
|
status: string
|
||||||
|
};
|
||||||
|
|
||||||
|
type MuiDialogProps = {
|
||||||
|
title?: {
|
||||||
|
name?: string;
|
||||||
|
icon?: string;
|
||||||
|
};
|
||||||
|
openDialog: boolean;
|
||||||
|
setOpenDialog: Function;
|
||||||
|
content?: ReactElement;
|
||||||
|
maxWidth?: string;
|
||||||
|
data?: DataContent | undefined;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type FormValuesProps = {
|
||||||
|
value: string;
|
||||||
|
active: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
const DialogUpdateStatus = ({ title, openDialog, setOpenDialog, data, maxWidth, content }: MuiDialogProps) => {
|
||||||
|
const NewCorporateSchema = Yup.object().shape({
|
||||||
|
reason: Yup.string().required('Corporate Status is required'),
|
||||||
|
});
|
||||||
|
|
||||||
|
const methods = useForm<FormValuesProps>({
|
||||||
|
resolver: yupResolver(NewCorporateSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
reset,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { isSubmitting },
|
||||||
|
} = methods;
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (openDialog === false) {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}, [openDialog, reset]);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setOpenDialog(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUpdate = (id: number, status: number) => {
|
||||||
|
axios
|
||||||
|
.put(`/corporates/${id}/activation`, {
|
||||||
|
// service_code: service.service_code,
|
||||||
|
active: status,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
handleClose()
|
||||||
|
window.location.reload();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
// console.log('asdasd', error.response.data.message)
|
||||||
|
enqueueSnackbar(
|
||||||
|
error.response.data.message ?? error.message ?? 'Failed Processing Request',
|
||||||
|
{ variant: 'error' }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let maxWidthDialog = 'md';
|
||||||
|
|
||||||
|
if (maxWidth) {
|
||||||
|
maxWidthDialog = maxWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSubmit = async (row : any) => {
|
||||||
|
console.log('test')
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={openDialog} onClose={handleClose} fullWidth={true} maxWidth={'sm'}>
|
||||||
|
<DialogTitle sx={{ backgroundColor: '#19BBBB', color: '#FFF', padding: 2 }}>
|
||||||
|
<Stack direction="row" alignItems="center" justifyContent="space-between">
|
||||||
|
{title?.icon ? (
|
||||||
|
<Stack direction="row">
|
||||||
|
<Iconify icon={title?.icon} width={25} height={25} sx={{ marginRight: '10px' }} />
|
||||||
|
<Typography variant="h6">{title?.name}</Typography>
|
||||||
|
</Stack>
|
||||||
|
) : (
|
||||||
|
<Typography variant="h6">{title?.name ? title?.name : ''}</Typography>
|
||||||
|
)}
|
||||||
|
<IconButton sx={{ color: '#FFF' }} onClick={handleClose}>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Stack>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent sx={{ backgroundColor: '#F9FAFB' }}>
|
||||||
|
|
||||||
|
{/* <Stack paddingX={2} paddingY={2}>
|
||||||
|
<Typography variant='subtitle1'>{description}</Typography>
|
||||||
|
</Stack>
|
||||||
|
<Card>
|
||||||
|
<Grid container paddingX={2} paddingY={2}>
|
||||||
|
<Grid item xs={4} md={4}>
|
||||||
|
<Typography variant='inherit'>Code</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={8}>
|
||||||
|
<Typography variant='subtitle1'>{data?.code}</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4} md={4} marginTop={2}>
|
||||||
|
<Typography variant='inherit'>Corporate Name</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={8} marginTop={2}>
|
||||||
|
<Typography variant='subtitle1'>{data?.name}</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Typography marginTop={5} marginBottom={3} variant='subtitle1'>
|
||||||
|
Reason for update*
|
||||||
|
</Typography>
|
||||||
|
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<RHFSelect
|
||||||
|
name="reason"
|
||||||
|
label="Reason for update"
|
||||||
|
>
|
||||||
|
<option value=""></option>
|
||||||
|
<option value="Agreement changed">Agreement changed</option>
|
||||||
|
<option value="Endorsement">Endorsement</option>
|
||||||
|
<option value="Renewal">Renewal</option>
|
||||||
|
<option value="Worng Setting">Worng Setting</option>
|
||||||
|
</RHFSelect>
|
||||||
|
</FormProvider>
|
||||||
|
<Stack
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="flex-end"
|
||||||
|
direction={{ xs: 'column', md: 'row' }}
|
||||||
|
spacing={2}
|
||||||
|
marginTop={5}
|
||||||
|
>
|
||||||
|
<Stack direction="row" spacing={1}>
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
boxShadow: 'none',
|
||||||
|
}}
|
||||||
|
variant="outlined"
|
||||||
|
size="medium"
|
||||||
|
fullWidth={true}
|
||||||
|
onClick={() => setOpenDialog(false)}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{data?.status == 1 ?
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
boxShadow: 'none',
|
||||||
|
}}
|
||||||
|
variant="contained"
|
||||||
|
size="medium"
|
||||||
|
fullWidth={true}
|
||||||
|
color='error'
|
||||||
|
onClick={() => handleUpdate(data?.id, 0)}
|
||||||
|
>
|
||||||
|
Inactive
|
||||||
|
</Button>
|
||||||
|
: <Button
|
||||||
|
sx={{
|
||||||
|
boxShadow: 'none',
|
||||||
|
}}
|
||||||
|
variant="contained"
|
||||||
|
size="medium"
|
||||||
|
fullWidth={true}
|
||||||
|
color='success'
|
||||||
|
onClick={() => handleUpdate(data?.id, 1)}
|
||||||
|
>
|
||||||
|
Active
|
||||||
|
</Button> }
|
||||||
|
</Stack>
|
||||||
|
</Stack> */}
|
||||||
|
{content}
|
||||||
|
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DialogUpdateStatus;
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { Corporate } from '@/@types/corporates';
|
||||||
|
import axios from '@/utils/axios';
|
||||||
|
import { ReactNode, createContext, useState, useEffect } from 'react';
|
||||||
|
import { useParams } from 'react-router';
|
||||||
|
// hooks
|
||||||
|
import useResponsive from '../hooks/useResponsive';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
export type ConfiguredCorporateContextProps = {
|
||||||
|
currentCorporate?: Corporate | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialState: ConfiguredCorporateContextProps = {
|
||||||
|
currentCorporate: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ConfiguredCorporateContext = createContext(initialState);
|
||||||
|
|
||||||
|
type ConfiguredCorporateProviderProps = {
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
function ConfiguredCorporateProvider({ children }: ConfiguredCorporateProviderProps) {
|
||||||
|
const { corporate_id } = useParams();
|
||||||
|
const [corporate, setCorporate] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
axios.get(`corporates/${corporate_id}`)
|
||||||
|
.then((res) => {
|
||||||
|
setCorporate(res.data)
|
||||||
|
})
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfiguredCorporateContext.Provider
|
||||||
|
value={{
|
||||||
|
currentCorporate: corporate,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ConfiguredCorporateContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ConfiguredCorporateProvider, ConfiguredCorporateContext };
|
||||||
@@ -32,6 +32,10 @@ const navConfig = [
|
|||||||
title: 'Alarm Center',
|
title: 'Alarm Center',
|
||||||
path: '/alarm-center',
|
path: '/alarm-center',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Formularium',
|
||||||
|
path: '/master/formularium-template-v2',
|
||||||
|
}
|
||||||
// {
|
// {
|
||||||
// title: 'Claim Submit',
|
// title: 'Claim Submit',
|
||||||
// path: '/claim-submit',
|
// path: '/claim-submit',
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
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 { ConfiguredCorporateContext } from "@/contexts/ConfiguredCorporateContext";
|
||||||
|
import { Corporate, CorporatePlan } from "@/@types/corporates";
|
||||||
|
import { MasterFormularium } from "./Type";
|
||||||
|
import CreateUpdateForm from "./CreateUpdateForm";
|
||||||
|
import Typography from "@/theme/overrides/Typography";
|
||||||
|
|
||||||
|
export default function CreateUpdate() {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { corporate_id, id } = useParams();
|
||||||
|
const [corporate, setCorporate] = useState<Corporate|null>();
|
||||||
|
const configuredCorporateContext = useContext(ConfiguredCorporateContext)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCorporate(configuredCorporateContext.currentCorporate);
|
||||||
|
}, [ConfiguredCorporateContext])
|
||||||
|
|
||||||
|
const [ currentCorporatePlan, setCurrentCorporatePlan ] = useState<CorporatePlan>();
|
||||||
|
const [ currentMasterForm, setCurrentMasterForm ] = useState<MasterFormularium>();
|
||||||
|
const isEdit = !!id;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEdit) {
|
||||||
|
axios.get(`/master/formularium-template/${id}/edit`)
|
||||||
|
.then((res) => {
|
||||||
|
// setCurrentCorporatePlan(res.data);
|
||||||
|
setCurrentMasterForm(res.data);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (err.response.status === 404) {
|
||||||
|
navigate('/404');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [corporate_id, id])
|
||||||
|
|
||||||
|
const pageType = !isEdit ? "Create" : "Edit"
|
||||||
|
const pageTitle = `Master Formularium ${pageType}`
|
||||||
|
return (
|
||||||
|
<Page title={pageTitle}>
|
||||||
|
<HeaderBreadcrumbs
|
||||||
|
heading={pageTitle}
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
name: 'Master',
|
||||||
|
href: '/master/formularium-template-v2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Formularium',
|
||||||
|
href: '/master/formularium-template-v2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: !isEdit ? 'Create' : 'Edit',
|
||||||
|
href: !isEdit ? `/master/formularium-template-v2/create` : `/master/formularium-template-v2/${id}/edit`
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<CreateUpdateForm isEdit={isEdit} currentMasterForm={currentMasterForm} />
|
||||||
|
|
||||||
|
</Page>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
import * as Yup from 'yup';
|
||||||
|
import { LoadingButton } from "@mui/lab";
|
||||||
|
import { Button, Card, Grid, Stack, Typography } from "@mui/material";
|
||||||
|
import { CorporatePlan } from "../../../@types/corporates";
|
||||||
|
import { FormProvider, 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 { MasterFormularium } from "./Type";
|
||||||
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isEdit: boolean;
|
||||||
|
currentMasterForm?: MasterFormularium;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function CreateUpdateForm({ isEdit, currentMasterForm }: Props) {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
|
||||||
|
const NewCorporatePlanSchema = Yup.object().shape({
|
||||||
|
name: Yup.string().required('Name is required'),
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultValues = useMemo(
|
||||||
|
() => ({
|
||||||
|
name: currentMasterForm?.name || '',
|
||||||
|
description: currentMasterForm?.description || '',
|
||||||
|
}),
|
||||||
|
[currentMasterForm]
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEdit && currentMasterForm) {
|
||||||
|
reset(defaultValues);
|
||||||
|
}
|
||||||
|
if (!isEdit) {
|
||||||
|
reset(defaultValues);
|
||||||
|
}
|
||||||
|
}, [isEdit, currentMasterForm])
|
||||||
|
|
||||||
|
const methods = useForm({
|
||||||
|
resolver: yupResolver(NewCorporatePlanSchema),
|
||||||
|
defaultValues,
|
||||||
|
})
|
||||||
|
|
||||||
|
const {
|
||||||
|
reset,
|
||||||
|
setError,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { isSubmitting }
|
||||||
|
} = methods;
|
||||||
|
|
||||||
|
const onSubmit = async (data: any) => {
|
||||||
|
if (!isEdit) {
|
||||||
|
await axios
|
||||||
|
.post('/master/formularium-template/store', data)
|
||||||
|
.then((res) => {
|
||||||
|
enqueueSnackbar('Formularium created succesfully', {variant: 'success'});
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
navigate('/master/formularium-template-v2', { 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 Reques', { variant: 'error' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
enqueueSnackbar('Create Failed : ' + response.data.message, {variant: 'error'});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await axios
|
||||||
|
.put(`/master/formularium-template/${currentMasterForm?.id}/update`, data)
|
||||||
|
.then((res) => {
|
||||||
|
enqueueSnackbar('Formularium updated successfully', { variant: 'success' });
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
navigate('/master/formularium-template-v2', { replace: true });
|
||||||
|
})
|
||||||
|
.catch(({ response }) => {
|
||||||
|
enqueueSnackbar(`Update Failed : ${response.data.message}`, { variant: 'error' })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Card sx={{ p:2 }}>
|
||||||
|
<Stack spacing={3}>
|
||||||
|
<Typography variant='h6' sx={{color: '#19BBBB'}}>Detail</Typography>
|
||||||
|
<Typography variant='h6'>Name*</Typography>
|
||||||
|
<RHFTextField name='name' label='Name' />
|
||||||
|
<Typography variant='h6'>Description*</Typography>
|
||||||
|
<RHFTextField name='description' label='Description' />
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
<Stack direction='row' spacing={4} sx={{marginTop: '40px'}}>
|
||||||
|
<Grid container item xs={12} justifyContent='flex-end' sx={{p:2}}>
|
||||||
|
<Button
|
||||||
|
variant='outlined'
|
||||||
|
onClick={() => navigate('/master/formularium-template-v2')}
|
||||||
|
sx={{
|
||||||
|
p:1,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
outlineColor: 'black',
|
||||||
|
marginRight: '20px',
|
||||||
|
width: 100
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<LoadingButton
|
||||||
|
loading={isSubmitting}
|
||||||
|
type='submit'
|
||||||
|
variant='contained'
|
||||||
|
sx={{
|
||||||
|
p:1,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
backgroundColor: '#19BBBB',
|
||||||
|
"&:hover":{
|
||||||
|
backgroundColor: '#19BBBB', color: '#FFF'
|
||||||
|
},
|
||||||
|
width: 100
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ isEdit? 'Update' : 'Create' }
|
||||||
|
</LoadingButton>
|
||||||
|
</Grid>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</FormProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
// @mui
|
||||||
|
import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Grid, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup, Pagination } from '@mui/material';
|
||||||
|
import { LoadingButton } from "@mui/lab";
|
||||||
|
import { CachedOutlined, FindInPageOutlined } from '@mui/icons-material';
|
||||||
|
// hooks
|
||||||
|
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||||
|
import useSettings from '../../../../hooks/useSettings';
|
||||||
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
import { RHFSelect, FormProvider } from '@/components/hook-form';
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
// components
|
||||||
|
import axios from '../../../../utils/axios';
|
||||||
|
import Label from '@/components/Label';
|
||||||
|
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||||
|
import DialogUpdateStatus from '@/components/DialogUpdateStatus'
|
||||||
|
import * as Yup from 'yup';
|
||||||
|
import { FormulariumData } from "../Type";
|
||||||
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
props: FormulariumData,
|
||||||
|
isActive: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DetailFormularium({props, isActive} : Props) {
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableBody>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell align='left' width={50} />
|
||||||
|
<TableCell align='left'>{props.code}</TableCell>
|
||||||
|
<TableCell align='left'>{props.atc_code}</TableCell>
|
||||||
|
<TableCell align='left'>{props.name}</TableCell>
|
||||||
|
<TableCell align='left'>{props.category_name}</TableCell>
|
||||||
|
<TableCell align='left'>{props.uom}</TableCell>
|
||||||
|
<TableCell align='left'>
|
||||||
|
{isActive == 1 ? (
|
||||||
|
<Label color='success'>Active</Label>
|
||||||
|
) : (
|
||||||
|
<Label color='error'>Inactive</Label>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align='center' width={100}>
|
||||||
|
<TableMoreMenu actions = {
|
||||||
|
<>
|
||||||
|
<MenuItem onClick={() => setOpen(!open)}>
|
||||||
|
<FindInPageOutlined />
|
||||||
|
Detail
|
||||||
|
</MenuItem>
|
||||||
|
</>
|
||||||
|
} />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={8} style={{paddingBottom: 0, paddingTop: 0}}>
|
||||||
|
<Collapse in={open} timeout='auto' unmountOnExit>
|
||||||
|
<Card sx={{paddingX:2, paddingY:2, marginBottom:3}}>
|
||||||
|
<Box sx={{margin: 1, pb: 2}}>
|
||||||
|
<Grid container>
|
||||||
|
<Grid item>
|
||||||
|
<Typography sx={{fontWeight: '600', mb: 1}}>Detail</Typography>
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs={2}>Description</Grid>
|
||||||
|
<Grid item xs={10}> : {props.description}</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={2}>General Indication</Grid>
|
||||||
|
<Grid item xs={10}> : {props.general_indication}</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={2}>Composition</Grid>
|
||||||
|
<Grid item xs={10}> : {props.composition}</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={2}>Kategori Obat</Grid>
|
||||||
|
<Grid item xs={10}> : {props.kategori_obat}</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={2}>BPOM Registration</Grid>
|
||||||
|
<Grid item xs={10}> : {props.bpom_registration}</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={2}>Classification</Grid>
|
||||||
|
<Grid item xs={10}> : {props.classifications}</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={2}>Cat For</Grid>
|
||||||
|
<Grid item xs={10}> : {props.cat_for}</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={2}>Class</Grid>
|
||||||
|
<Grid item xs={10}> : {props.class}</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={2}>Manufacturer</Grid>
|
||||||
|
<Grid item xs={10}> : {props.manufacturer}</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</Card>
|
||||||
|
</Collapse>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
// @mui
|
||||||
|
import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Grid, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup, Pagination } from '@mui/material';
|
||||||
|
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||||
|
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||||
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
|
import UploadIcon from '@mui/icons-material/Upload';
|
||||||
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
// hooks
|
||||||
|
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||||
|
import useSettings from '../../../../hooks/useSettings';
|
||||||
|
import { useLocation, useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
// components
|
||||||
|
import axios from '../../../../utils/axios';
|
||||||
|
import { LaravelPaginatedData } from '../../../../@types/paginated-data';
|
||||||
|
import { Icd } from '../../../../@types/diagnosis';
|
||||||
|
import BasePagination from '../../../../components/BasePagination';
|
||||||
|
import { enqueueSnackbar } from 'notistack';
|
||||||
|
import DetailFormularium from "./DetailFormularium";
|
||||||
|
import { FormulariumData } from '../Type';
|
||||||
|
|
||||||
|
|
||||||
|
export default function List() {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { id: formularium_template_id } = useParams();
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
|
const [importResult, setImportResult] = useState(null);
|
||||||
|
const { isActive } = useLocation().state as { isActive: number }
|
||||||
|
|
||||||
|
function SearchInput(props: any) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSearchText(searchParams.get('search') ?? '');
|
||||||
|
}, [searchParams])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSearchSubmit} style={{width: '100%'}}>
|
||||||
|
<TextField
|
||||||
|
id='search-input'
|
||||||
|
ref={searchInput}
|
||||||
|
label='search'
|
||||||
|
variant='outlined'
|
||||||
|
fullWidth
|
||||||
|
onChange={handleSearchChange}
|
||||||
|
value={searchText}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ImportForm( props: any ) {
|
||||||
|
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 handleCancelImportButton = () => {
|
||||||
|
importForm.current.value = '';
|
||||||
|
importForm.current?.dispatchEvent(new Event('change', { bubbles: true }))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleGetTemplate = (type: string) => {
|
||||||
|
axios.get('corporates/import-document-example/' + type)
|
||||||
|
.then((response) => {
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = response.data.data.file_url;
|
||||||
|
link.setAttribute('download', response.data.data.file_name);
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
handleClose();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleImportChange = (event: any) => {
|
||||||
|
if (event.target.files[0]) {
|
||||||
|
setCurrentImportFileName(event.target.files[0].name)
|
||||||
|
} else {
|
||||||
|
setCurrentImportFileName(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleFormulariumList = async (appliedFilter = null) => {
|
||||||
|
axios.get(`master/formulariums/${formularium_template_id}/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();
|
||||||
|
enqueueSnackbar('Download Success', { variant: 'success' })
|
||||||
|
})
|
||||||
|
.catch(response => {
|
||||||
|
enqueueSnackbar('Looks like something went wrong. Please check your data and try again. ' + response.message, { variant: 'error' })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpload = () => {
|
||||||
|
if (importForm.current?.files?.length) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', importForm.current?.files[0])
|
||||||
|
axios.post(`master/formulariums/${formularium_template_id}/import`, formData )
|
||||||
|
.then(response => {
|
||||||
|
handleCancelImportButton();
|
||||||
|
loadDataTableData();
|
||||||
|
setImportResult(response.data);
|
||||||
|
})
|
||||||
|
.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' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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}/>
|
||||||
|
<Button
|
||||||
|
id='import-button'
|
||||||
|
variant='outlined'
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
sx={{
|
||||||
|
p: 1.8,
|
||||||
|
width: '200px',
|
||||||
|
backgroundColor: '#19BBBB', color: '#FFF',
|
||||||
|
"&:hover":{
|
||||||
|
backgroundColor: "#19BBBB", color: '#FFF'
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded={createMenu ? 'true' : undefined}
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
Create
|
||||||
|
</Button>
|
||||||
|
<Menu
|
||||||
|
id='import-button'
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={createMenu}
|
||||||
|
onClose={handleClose}
|
||||||
|
MenuListProps={{
|
||||||
|
'aria-labelledby': 'basic-button',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem onClick={handleImportButton}>Import</MenuItem>
|
||||||
|
<MenuItem onClick={() => handleGetTemplate('master-formularium')}>Download Template</MenuItem>
|
||||||
|
<MenuItem onClick={() => handleFormulariumList()}>Download Formularium</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
{( currentImportFileName && <Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||||
|
<ButtonGroup
|
||||||
|
variant='outlined'
|
||||||
|
aria-label='outlined button group'
|
||||||
|
fullWidth
|
||||||
|
>
|
||||||
|
<Button onClick={handleImportButton} fullWidth>{currentImportFileName ?? "No File Selected"}</Button>
|
||||||
|
<Button onClick={handleCancelImportButton} size='small' fullWidth={false} sx={{ p:1.8 }}>
|
||||||
|
<CancelIcon color='error'/>
|
||||||
|
</Button>
|
||||||
|
</ButtonGroup>
|
||||||
|
<Button
|
||||||
|
id='upload-button'
|
||||||
|
variant='outlined'
|
||||||
|
startIcon={<UploadIcon />}
|
||||||
|
sx={{ p: 1.8 }}
|
||||||
|
onClick={handleUpload}
|
||||||
|
>
|
||||||
|
Upload
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
{( importResult &&
|
||||||
|
<Stack direction={'row'} sx={{ px: 2, pb: 2 }}>
|
||||||
|
<Box sx={{ color: 'text.secondary'}}>Last Import Result Report : <a href={importResult.result_file?.url ?? "#"}>{importResult.result_file?.name ?? "-"}</a></Box>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default data
|
||||||
|
const [dataTableRow, setDataTableRow] = useState<FormulariumData[] | null>(null)
|
||||||
|
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||||
|
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 loadDataTableData = async (appliedFilter : any | null = null) => {
|
||||||
|
setDataTableLoading(true);
|
||||||
|
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||||
|
const response = await axios.get(`/master/formulariums/${formularium_template_id}`, { params: filter });
|
||||||
|
setDataTableLoading(false);
|
||||||
|
|
||||||
|
console.log(formularium_template_id)
|
||||||
|
console.log(response)
|
||||||
|
setDataTableData(response.data)
|
||||||
|
setDataTableRow(response.data.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const applyFilter = async (searchFilter: string) => {
|
||||||
|
await loadDataTableData({ 'search': searchFilter });
|
||||||
|
setSearchParams({ 'search' : searchFilter });
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePageChange = (event : ChangeEvent, value: number) => {
|
||||||
|
const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]);
|
||||||
|
loadDataTableData(filter);
|
||||||
|
setSearchParams(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadDataTableData();
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const headStyle = {
|
||||||
|
fontWeight: 'bold',
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack>
|
||||||
|
<ImportForm />
|
||||||
|
<Card>
|
||||||
|
<TableContainer component={Paper}>
|
||||||
|
<Table aria-label='collapsible table'>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell style={headStyle} align='left' width={50}/>
|
||||||
|
<TableCell style={headStyle} align='left'>Code</TableCell>
|
||||||
|
<TableCell style={headStyle} align='left'>ATC Code</TableCell>
|
||||||
|
<TableCell style={headStyle} align='left'>Name</TableCell>
|
||||||
|
<TableCell style={headStyle} align='left'>Category Name</TableCell>
|
||||||
|
<TableCell style={headStyle} align='left'>UOM</TableCell>
|
||||||
|
<TableCell style={headStyle} align='left'>Status</TableCell>
|
||||||
|
<TableCell style={headStyle} align='center' width={100}></TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
{dataTableIsLoading ? (
|
||||||
|
<TableBody>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={8} align='center'>
|
||||||
|
Loading
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
) : dataTableData.data.length == 0 ? (
|
||||||
|
<TableBody>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={8} align='center'>
|
||||||
|
No Data
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
) : (
|
||||||
|
dataTableRow?.map(item => (
|
||||||
|
<DetailFormularium props={item} isActive={1}/>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
|
||||||
|
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||||
|
</Card>
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
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 "./Formularium";
|
||||||
|
|
||||||
|
|
||||||
|
export default function Formularium() {
|
||||||
|
const pageTitle = "Formularium"
|
||||||
|
const { id: formularium_template_id } = useParams();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page title={ pageTitle }>
|
||||||
|
<HeaderBreadcrumbs
|
||||||
|
heading={ pageTitle }
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
name: 'Master',
|
||||||
|
href: '/master/formularium-template-v2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Formularium',
|
||||||
|
href: '/master/formularium-template-v2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Detail',
|
||||||
|
href: `/master/formularium-template-v2/${formularium_template_id}/detail`
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Card>
|
||||||
|
<List />
|
||||||
|
</Card>
|
||||||
|
</Page>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
import * as Yup from 'yup';
|
||||||
|
import TableMoreMenu from "@/components/table/TableMoreMenu"
|
||||||
|
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||||
|
import CachedOutlinedIcon from '@mui/icons-material/CachedOutlined';
|
||||||
|
import HistoryIcon from '@mui/icons-material/History';
|
||||||
|
import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined';
|
||||||
|
import { Button, Card, Collapse, Grid, MenuItem, Paper, Stack, Table, TableCell, TableContainer, TableHead, TableRow, Typography } from "@mui/material"
|
||||||
|
import React, { Fragment, useEffect, useState } from "react";
|
||||||
|
import axios from "@/utils/axios";
|
||||||
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
|
import { RHFSelect, FormProvider } from '@/components/hook-form';
|
||||||
|
import DialogUpdateStatus from '@/components/DialogUpdateStatus'
|
||||||
|
import { MasterFormularium } from "./Type";
|
||||||
|
import { LoadingButton } from "@mui/lab";
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
props: MasterFormularium
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FormulariumRow({props} : Props) {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const [isDialogOpen, setDialogOpen] = useState(false);
|
||||||
|
const [dataValue, setDataValue] = useState<MasterFormularium | null>(null);
|
||||||
|
const [dataDescription, setDescriptionValue] = useState('');
|
||||||
|
const [url, setUrl] = useState('');
|
||||||
|
let titles = {
|
||||||
|
name: 'Update Status',
|
||||||
|
icon: '-'
|
||||||
|
}
|
||||||
|
type FormValuesProps = {
|
||||||
|
value: string;
|
||||||
|
active: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleActivate = (isOpen: boolean, dataValue: MasterFormularium) => {
|
||||||
|
setDialogOpen(isOpen);
|
||||||
|
setDataValue(dataValue);
|
||||||
|
setDescriptionValue("Are you sure to inactive this formularium ? ");
|
||||||
|
setUrl(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const NewMasterFormSchema = Yup.object().shape({
|
||||||
|
reason: Yup.string().required('Reason edit is required')
|
||||||
|
});
|
||||||
|
|
||||||
|
const methods = useForm<FormValuesProps>({
|
||||||
|
resolver: yupResolver(NewMasterFormSchema)
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = async (row: any) => {
|
||||||
|
try {
|
||||||
|
handleUpdate(dataValue?.active, dataValue?.id, row.reason)
|
||||||
|
} catch (error: any) {
|
||||||
|
console.log('data gagal');
|
||||||
|
}
|
||||||
|
|
||||||
|
const ascent = document?.querySelector('ascent');
|
||||||
|
if (ascent != null) {
|
||||||
|
ascent.innerHTML = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUpdate = (active: number, id: number, reason: string) => {
|
||||||
|
|
||||||
|
if (active == 1) {
|
||||||
|
active = 0
|
||||||
|
} else {
|
||||||
|
active = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
axios
|
||||||
|
.put(`/master/formularium-template/${id}/activation`, {
|
||||||
|
active: active,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
window.location.reload();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
reset,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { isSubmitting },
|
||||||
|
} = methods;
|
||||||
|
|
||||||
|
const getContent = () => (
|
||||||
|
<>
|
||||||
|
<Stack paddingX={2} paddingY={2}>
|
||||||
|
<Typography variant='subtitle1'>Are you sure to Change this Formularium</Typography>
|
||||||
|
<Stack>
|
||||||
|
<Card>
|
||||||
|
<Grid container paddingX={2} paddingY={2}>
|
||||||
|
<Grid item xs={5} md={5}>
|
||||||
|
<Typography variant="inherit">Formularium name</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={7}>
|
||||||
|
<Typography variant="subtitle1">{dataValue?.name}</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Typography marginTop={5} marginBottom={3} variant="subtitle1">Reason for update</Typography>
|
||||||
|
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<RHFSelect
|
||||||
|
name="reason"
|
||||||
|
label="Reason for update"
|
||||||
|
>
|
||||||
|
<option value=""></option>
|
||||||
|
<option value="Agreement changed">Agreement changed</option>
|
||||||
|
<option value="Endorsement">Endorsement</option>
|
||||||
|
<option value="Renewal">Renewal</option>
|
||||||
|
<option value="Wrong Setting">Wrong Setting</option>
|
||||||
|
</RHFSelect>
|
||||||
|
<Stack
|
||||||
|
alignItems='center'
|
||||||
|
justifyContent='flex-end'
|
||||||
|
direction={{xs: 'column', md: 'row'}}
|
||||||
|
spacing={2}
|
||||||
|
marginTop={5}
|
||||||
|
>
|
||||||
|
<Stack direction='row' spacing={1}>
|
||||||
|
<Button
|
||||||
|
sx={{boxShadow: 'none'}}
|
||||||
|
variant='outlined'
|
||||||
|
size='medium'
|
||||||
|
fullWidth={true}
|
||||||
|
onClick={() => setDialogOpen(false)}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
{dataValue?.active == 1 ?
|
||||||
|
<LoadingButton
|
||||||
|
sx={{boxShadow: '0px 2px 4px rgba(0,0,0,0.1)'}}
|
||||||
|
type='submit'
|
||||||
|
variant='contained'
|
||||||
|
size='medium'
|
||||||
|
fullWidth={true}
|
||||||
|
loading={isSubmitting}
|
||||||
|
color='error'
|
||||||
|
>
|
||||||
|
Inactive
|
||||||
|
</LoadingButton> :
|
||||||
|
<LoadingButton
|
||||||
|
sx={{boxShadow: '0px 2px 4px rgba(0,0,0,0.1)'}}
|
||||||
|
type='submit'
|
||||||
|
variant='contained'
|
||||||
|
size='medium'
|
||||||
|
fullWidth={true}
|
||||||
|
loading={isSubmitting}
|
||||||
|
color='success'
|
||||||
|
>
|
||||||
|
Active
|
||||||
|
</LoadingButton>
|
||||||
|
}
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</FormProvider>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell align="left" width={50}></TableCell>
|
||||||
|
<TableCell align="left">{props.name}</TableCell>
|
||||||
|
<TableCell align="left">{props.description}</TableCell>
|
||||||
|
<TableCell align="center" width={100}>
|
||||||
|
<TableMoreMenu actions = {
|
||||||
|
<>
|
||||||
|
<MenuItem onClick={() => navigate(`/master/formularium-template-v2/${props.id}/detail`, {state: { isActive: props.active }})}>
|
||||||
|
<FindInPageOutlinedIcon />
|
||||||
|
Detail
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem onClick={() => navigate(`/master/formularium-template-v2/${props.id}/edit`)}>
|
||||||
|
<EditOutlinedIcon />
|
||||||
|
Edit
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem onClick={() => handleActivate(true, {
|
||||||
|
id: props.id,
|
||||||
|
name: props.name,
|
||||||
|
description: props.description,
|
||||||
|
active: props.active
|
||||||
|
})
|
||||||
|
}>
|
||||||
|
<CachedOutlinedIcon />
|
||||||
|
Update Status
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem onClick={() => navigate(`/master/formularium-template-v2/${props.id}/history`)}>
|
||||||
|
<HistoryIcon />
|
||||||
|
History
|
||||||
|
</MenuItem>
|
||||||
|
</>
|
||||||
|
} />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<DialogUpdateStatus
|
||||||
|
openDialog={isDialogOpen}
|
||||||
|
setOpenDialog={setDialogOpen}
|
||||||
|
description={dataDescription}
|
||||||
|
title={titles}
|
||||||
|
data={dataValue}
|
||||||
|
content={getContent()}
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
// @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,0.5)'
|
||||||
|
: 'rgba(0,0,0,.03)',
|
||||||
|
flexDirection: 'row-reverse',
|
||||||
|
"& .MuiAccordionSummary-expandIconWrapper.Mui-expanded": {
|
||||||
|
transform: 'rotate(90dg)',
|
||||||
|
},
|
||||||
|
"& .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 MasterFormulariumHistory() {
|
||||||
|
const [expanded, setExpanded] = React.useState<string | false>('panel1');
|
||||||
|
|
||||||
|
const handleChange = (panel: string) => (event: React.SyntheticEvent, newExpanded: boolean) => {
|
||||||
|
setExpanded(newExpanded ? panel : false);
|
||||||
|
};
|
||||||
|
const pageTitle = 'Master Formularium History'
|
||||||
|
const { id } = useParams();
|
||||||
|
const { corporate_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\\FormulariumTemplate';
|
||||||
|
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/formularium-template-v2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Formularium',
|
||||||
|
href: '/master/formularium-template-v2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'History',
|
||||||
|
href: `/master/formularium-template-v2/${id}`
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
{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>
|
||||||
|
<TableContainer component={Paper}>
|
||||||
|
<Table aria-label='collapsible table'>
|
||||||
|
<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 '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 align="center">{`${field}`}</TableCell>
|
||||||
|
<TableCell align="center">{`${value}`}</TableCell>
|
||||||
|
<TableCell align="center">{renderedValue}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</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 MasterFormularium() {
|
||||||
|
const pageTitle = "Master Formularium"
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page title={ pageTitle }>
|
||||||
|
<HeaderBreadcrumbs
|
||||||
|
heading={pageTitle}
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
name: "Master",
|
||||||
|
href: "/master/formularium-template-v2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Formularium",
|
||||||
|
href: "/master/formularium-template-v2"
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<List />
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
</Page>
|
||||||
|
)
|
||||||
|
}
|
||||||
179
frontend/client-portal/src/pages/Master/FormulariumV2/List.tsx
Normal file
179
frontend/client-portal/src/pages/Master/FormulariumV2/List.tsx
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
// @mui
|
||||||
|
import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Grid, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup, Pagination } from '@mui/material';
|
||||||
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
|
// hooks
|
||||||
|
import React, { ChangeEvent, Component, useEffect, useContext, useRef, useState } from 'react';
|
||||||
|
import useSettings from '../../../hooks/useSettings';
|
||||||
|
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
// components
|
||||||
|
import axios from '../../../utils/axios';
|
||||||
|
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||||
|
import BasePagination from '../../../components/BasePagination';
|
||||||
|
import FormulariumRow from "./FormulariumRow";
|
||||||
|
import { MasterFormularium } from "./Type";
|
||||||
|
import { UserCurrentCorporateContext } from '../../../contexts/UserCurrentCorporate';
|
||||||
|
|
||||||
|
export default function List() {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
|
|
||||||
|
// Default data
|
||||||
|
const [dataTableRow, setDataTableRow] = useState<MasterFormularium[] | null>(null)
|
||||||
|
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||||
|
const { corporateValue } = useContext(UserCurrentCorporateContext);
|
||||||
|
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 loadDataTableData =async (appliedFilter: any | null = null) => {
|
||||||
|
setDataTableLoading(true);
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
...Object.fromEntries([...searchParams.entries()]), // Mengambil parameter dari searchParams
|
||||||
|
corporate_id: corporateValue, // Menambahkan corporate_id
|
||||||
|
...(appliedFilter ? appliedFilter : {}) // Menggabungkan dengan appliedFilter jika ada
|
||||||
|
};
|
||||||
|
const response = await axios.get('/master/formularium-template', { params: filter });
|
||||||
|
console.log(response.data);
|
||||||
|
console.log(response.data.data)
|
||||||
|
setDataTableLoading(false);
|
||||||
|
|
||||||
|
setDataTableData(response.data);
|
||||||
|
setDataTableRow(response.data.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const applyFilter = async (searchFilter: string) => {
|
||||||
|
await loadDataTableData({'search' : searchFilter });
|
||||||
|
setSearchParams({ 'search' : searchFilter })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePageChange = (event : ChangeEvent, value: number) => {
|
||||||
|
const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]);
|
||||||
|
loadDataTableData(filter);
|
||||||
|
setSearchParams(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadDataTableData();
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
function SearchInput(props: any) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSearchText(searchParams.get('search') ?? '');
|
||||||
|
}, [searchParams])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSearchSubmit} style={{width: '100%'}}>
|
||||||
|
<TextField
|
||||||
|
id='search-input'
|
||||||
|
ref={searchInput}
|
||||||
|
label='Search'
|
||||||
|
variant='outlined'
|
||||||
|
fullWidth
|
||||||
|
onChange={handleSearchChange}
|
||||||
|
value={searchText}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SearchCreate(props: any) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Stack direction={'row'} spacing={2} sx={{p:2}}>
|
||||||
|
<SearchInput onSearch={applyFilter}/>
|
||||||
|
{/* <Button
|
||||||
|
id='create-button'
|
||||||
|
variant='contained'
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
onClick={() => navigate('/master/formularium-template-v2/create')}
|
||||||
|
sx={{
|
||||||
|
p: 1.8,
|
||||||
|
width: '200px',
|
||||||
|
backgroundColor: '#19BBBB', color: '#FFF',
|
||||||
|
"&:hover":{
|
||||||
|
backgroundColor: "#19BBBB", color: '#FFF'
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Create
|
||||||
|
</Button> */}
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const headStyle = {
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<Stack>
|
||||||
|
<SearchCreate />
|
||||||
|
<Card>
|
||||||
|
<TableContainer component={Paper}>
|
||||||
|
<Table aria-label='collapsible table'>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell align='left' width={50}></TableCell>
|
||||||
|
<TableCell align='left' style={headStyle}>Name</TableCell>
|
||||||
|
<TableCell align='left' style={headStyle}>Description</TableCell>
|
||||||
|
<TableCell align='center' style={headStyle} width={100}></TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
{dataTableIsLoading ? (
|
||||||
|
<TableBody>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={4} align='center'>
|
||||||
|
Loading
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
) : dataTableData.data.length == 0 ? (
|
||||||
|
<TableBody>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={4} align='center'>
|
||||||
|
No Data
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
) : (
|
||||||
|
<TableBody>
|
||||||
|
{dataTableRow?.map(item => (
|
||||||
|
<FormulariumRow key={item.id} props={item}/>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
)}
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||||
|
</Card>
|
||||||
|
</Stack>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
export type MasterFormularium = {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
active: number
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type FormulariumData = {
|
||||||
|
id: number
|
||||||
|
code: string
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
manufacturer: string
|
||||||
|
category_name: string
|
||||||
|
kategori_obat: string
|
||||||
|
uom: string
|
||||||
|
general_indication: string
|
||||||
|
composition: string
|
||||||
|
atc_code: string
|
||||||
|
class: string
|
||||||
|
bpom_registration: string
|
||||||
|
classifications: string
|
||||||
|
cat_for: string
|
||||||
|
created_at: string
|
||||||
|
updated_at: string
|
||||||
|
deleted_at: any
|
||||||
|
created_by: number
|
||||||
|
updated_by: number
|
||||||
|
deleted_by: any
|
||||||
|
formularium_template_id: number
|
||||||
|
}
|
||||||
@@ -234,6 +234,86 @@ export default function Router() {
|
|||||||
{ path: '*', element: <Navigate to="/404" replace /> },
|
{ path: '*', element: <Navigate to="/404" replace /> },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'master/formularium-template-v2',
|
||||||
|
element: (
|
||||||
|
<AuthProvider>
|
||||||
|
<AuthGuard>
|
||||||
|
<DashboardLayout />
|
||||||
|
</AuthGuard>
|
||||||
|
</AuthProvider>
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
element: <MasterFormulariumTemplateV2 />,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'master/formularium-template-v2/:id/detail',
|
||||||
|
element: (
|
||||||
|
<AuthProvider>
|
||||||
|
<AuthGuard>
|
||||||
|
<DashboardLayout />
|
||||||
|
</AuthGuard>
|
||||||
|
</AuthProvider>
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
element: <MasterFormulariumTemplateDetailV2 />,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'master/formularium-template-v2/create',
|
||||||
|
element: (
|
||||||
|
<AuthProvider>
|
||||||
|
<AuthGuard>
|
||||||
|
<DashboardLayout />
|
||||||
|
</AuthGuard>
|
||||||
|
</AuthProvider>
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
element: <MasterFormulariumTemplateCreateV2 />,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'master/formularium-template-v2/:id/edit',
|
||||||
|
element: (
|
||||||
|
<AuthProvider>
|
||||||
|
<AuthGuard>
|
||||||
|
<DashboardLayout />
|
||||||
|
</AuthGuard>
|
||||||
|
</AuthProvider>
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
element: <MasterFormulariumTemplateCreateV2 />,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'master/formularium-template-v2/:id/history',
|
||||||
|
element: (
|
||||||
|
<AuthProvider>
|
||||||
|
<AuthGuard>
|
||||||
|
<DashboardLayout />
|
||||||
|
</AuthGuard>
|
||||||
|
</AuthProvider>
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
element: <MasterFormulariumTemplateHistoriesV2 />,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{ path: '*', element: <Navigate to="/404" replace /> },
|
{ path: '*', element: <Navigate to="/404" replace /> },
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -275,3 +355,9 @@ const ClaimRequest = Loadable(lazy(() => import('../pages/ClaimSubmit/DialogDeta
|
|||||||
const Corporate = Loadable(lazy(() => import('../pages/Corporate/Index')));
|
const Corporate = Loadable(lazy(() => import('../pages/Corporate/Index')));
|
||||||
const CorporateEdit = Loadable(lazy(() => import('../pages/Corporate/Form')));
|
const CorporateEdit = Loadable(lazy(() => import('../pages/Corporate/Form')));
|
||||||
const CorporateShow = Loadable(lazy(() => import('../pages/Corporate/Show')));
|
const CorporateShow = Loadable(lazy(() => import('../pages/Corporate/Show')));
|
||||||
|
|
||||||
|
// Formularium
|
||||||
|
const MasterFormulariumTemplateV2 = Loadable(lazy(() => import('../pages/Master/FormulariumV2/Index')));
|
||||||
|
const MasterFormulariumTemplateCreateV2 = Loadable(lazy(() => import('../pages/Master/FormulariumV2/CreateUpdate')));
|
||||||
|
const MasterFormulariumTemplateHistoriesV2 = Loadable(lazy(() => import('../pages/Master/FormulariumV2/History')));
|
||||||
|
const MasterFormulariumTemplateDetailV2 = Loadable(lazy(() => import('../pages/Master/FormulariumV2/Detail/Index')));
|
||||||
|
|||||||
@@ -30,6 +30,13 @@ export type Specialities = {
|
|||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PeriodStart = {
|
||||||
|
date: string;
|
||||||
|
};
|
||||||
|
export type PeriodEnd = {
|
||||||
|
date: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type Practitioner = {
|
export type Practitioner = {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -50,6 +57,35 @@ export type Practitioner = {
|
|||||||
active: boolean | number;
|
active: boolean | number;
|
||||||
organizations?: Organizations[];
|
organizations?: Organizations[];
|
||||||
specialities?: Specialities[];
|
specialities?: Specialities[];
|
||||||
|
period_start?: PeriodStart[];
|
||||||
|
period_end?: PeriodEnd[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Medicine = {
|
||||||
|
id: number;
|
||||||
|
drug_id: number;
|
||||||
|
unit_id: number;
|
||||||
|
qty: number;
|
||||||
|
signa: string;
|
||||||
|
note: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Appointment = {
|
||||||
|
id:number|undefined;
|
||||||
|
name:string;
|
||||||
|
address:string;
|
||||||
|
birth_date:string;
|
||||||
|
gender:string;
|
||||||
|
description:string;
|
||||||
|
birth_place:string;
|
||||||
|
active:number;
|
||||||
|
avatar_url:string;
|
||||||
|
doctor_id:number;
|
||||||
|
organizations:Organizations[];
|
||||||
|
specialities:Specialities[];
|
||||||
|
diagnosis:string;
|
||||||
|
hospital:string;
|
||||||
|
medicine: Medicine[];
|
||||||
|
}
|
||||||
|
|
||||||
export type PractitionerType = Practitioner;
|
export type PractitionerType = Practitioner;
|
||||||
@@ -19,6 +19,8 @@ export const accessGroup = {
|
|||||||
admin: ["/report/logs"]
|
admin: ["/report/logs"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const navConfig = [
|
const navConfig = [
|
||||||
// GENERAL
|
// GENERAL
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
@@ -95,11 +97,12 @@ const navConfig = [
|
|||||||
{
|
{
|
||||||
title: 'REPORT',
|
title: 'REPORT',
|
||||||
children: [
|
children: [
|
||||||
|
{ title: 'Files Provider', path: 'report/files-provider'},
|
||||||
{ title: 'Letter of Guarantee', path: '/report/logs' },
|
{ title: 'Letter of Guarantee', path: '/report/logs' },
|
||||||
{ title: 'Appointment', path: '/report/appointments' },
|
{ title: 'Appointment', path: '/report/appointments' },
|
||||||
{ title: 'Live Chat', path: '/report/live-chat' },
|
{ title: 'Live Chat', path: '/report/live-chat' },
|
||||||
{ title: 'Linksehat Payment', path: '/report/linksehat-payments' },
|
{ title: 'Linksehat Payment', path: '/report/linksehat-payments' },
|
||||||
{ title: 'Prescription', path: '/report/prescription' },
|
// { title: 'Prescription', path: '/report/prescription' },
|
||||||
{ title: 'Doctor Rating', path: '/report/doctorrating' },
|
{ title: 'Doctor Rating', path: '/report/doctorrating' },
|
||||||
|
|
||||||
],
|
],
|
||||||
@@ -122,6 +125,10 @@ const navConfig = [
|
|||||||
title: 'LINKING TOOLS',
|
title: 'LINKING TOOLS',
|
||||||
path: '/linking',
|
path: '/linking',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'E-PRESCRIPTION',
|
||||||
|
path: '/e-prescription/live-chat',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import navConfig from './NavConfig';
|
|||||||
import NavbarDocs from './NavbarDocs';
|
import NavbarDocs from './NavbarDocs';
|
||||||
import NavbarAccount from './NavbarAccount';
|
import NavbarAccount from './NavbarAccount';
|
||||||
import CollapseButton from './CollapseButton';
|
import CollapseButton from './CollapseButton';
|
||||||
|
import useAuth from '@/hooks/useAuth';
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@ export default function NavbarVertical({ isOpenSidebar, onCloseSidebar }: Props)
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
|
const {user} = useAuth()
|
||||||
|
|
||||||
const isDesktop = useResponsive('up', 'lg');
|
const isDesktop = useResponsive('up', 'lg');
|
||||||
|
|
||||||
@@ -55,6 +57,16 @@ export default function NavbarVertical({ isOpenSidebar, onCloseSidebar }: Props)
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [pathname]);
|
}, [pathname]);
|
||||||
|
|
||||||
|
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 renderContent = (
|
const renderContent = (
|
||||||
<Scrollbar
|
<Scrollbar
|
||||||
sx={{
|
sx={{
|
||||||
@@ -89,7 +101,7 @@ export default function NavbarVertical({ isOpenSidebar, onCloseSidebar }: Props)
|
|||||||
<NavbarAccount isCollapse={isCollapse} />
|
<NavbarAccount isCollapse={isCollapse} />
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<NavSectionVertical navConfig={navConfig} isCollapse={isCollapse} />
|
<NavSectionVertical navConfig={user.role_id == 5 ? filteredData : navConfig} isCollapse={isCollapse} />
|
||||||
|
|
||||||
<Box sx={{ flexGrow: 1 }} />
|
<Box sx={{ flexGrow: 1 }} />
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ export default function DialogEditFinalLOG({requestLog, setOpenDialog, openDialo
|
|||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
|
billing_no: requestLog?.billing_no,
|
||||||
|
invoice_no: requestLog?.invoice_no,
|
||||||
discharge_date: requestLog?.discharge_date,
|
discharge_date: requestLog?.discharge_date,
|
||||||
id: requestLog?.id,
|
id: requestLog?.id,
|
||||||
catatan: requestLog?.catatan,
|
catatan: requestLog?.catatan,
|
||||||
@@ -49,6 +51,8 @@ export default function DialogEditFinalLOG({requestLog, setOpenDialog, openDialo
|
|||||||
if (requestLog) {
|
if (requestLog) {
|
||||||
setFormData({
|
setFormData({
|
||||||
discharge_date: requestLog.discharge_date,
|
discharge_date: requestLog.discharge_date,
|
||||||
|
billing_no: requestLog.billing_no,
|
||||||
|
invoice_no: requestLog.invoice_no,
|
||||||
id: requestLog.id,
|
id: requestLog.id,
|
||||||
catatan: requestLog.catatan,
|
catatan: requestLog.catatan,
|
||||||
icdCodes: requestLog.diagnosis
|
icdCodes: requestLog.diagnosis
|
||||||
@@ -116,6 +120,8 @@ export default function DialogEditFinalLOG({requestLog, setOpenDialog, openDialo
|
|||||||
setFormData({
|
setFormData({
|
||||||
discharge_date: requestLog?.discharge_date,
|
discharge_date: requestLog?.discharge_date,
|
||||||
id: requestLog?.id,
|
id: requestLog?.id,
|
||||||
|
billing_no: requestLog?.billing_no,
|
||||||
|
invoice_no: requestLog?.invoice_no,
|
||||||
catatan: requestLog?.catatan,
|
catatan: requestLog?.catatan,
|
||||||
icdCodes: requestLog?.diagnosis
|
icdCodes: requestLog?.diagnosis
|
||||||
? requestLog?.diagnosis.map(diagnosis => diagnosis.code)
|
? requestLog?.diagnosis.map(diagnosis => diagnosis.code)
|
||||||
@@ -173,6 +179,26 @@ export default function DialogEditFinalLOG({requestLog, setOpenDialog, openDialo
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card sx={{padding:2, marginTop:2}} >
|
<Card sx={{padding:2, marginTop:2}} >
|
||||||
|
<Stack direction='row' spacing={2} sx={marginBottom2}>
|
||||||
|
<Typography variant='subtitle2' sx={style1} gutterBottom>Invoice Number</Typography>
|
||||||
|
<TextField
|
||||||
|
label="Invoice Number"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
value={formData.invoice_no}
|
||||||
|
onChange={(e) => handleChange('invoice_no', e.target.value)}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
<Stack direction='row' spacing={2} sx={marginBottom2}>
|
||||||
|
<Typography variant='subtitle2' sx={style1} gutterBottom>Billing Number</Typography>
|
||||||
|
<TextField
|
||||||
|
label="Billing Number"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
value={formData.billing_no}
|
||||||
|
onChange={(e) => handleChange('billing_no', e.target.value)}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
<Stack direction='row' spacing={2} sx={marginBottom2}>
|
<Stack direction='row' spacing={2} sx={marginBottom2}>
|
||||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Discharge Date</Typography>
|
<Typography variant='subtitle2' sx={style1} gutterBottom>Discharge Date</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
|
|||||||
@@ -182,6 +182,14 @@ export default function Detail() {
|
|||||||
</Grid>) : null }
|
</Grid>) : null }
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
||||||
|
<Typography variant='subtitle2' sx={style1} gutterBottom>Invoice Number</Typography>
|
||||||
|
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.invoice_no ? requestLog?.invoice_no : '-'}</Typography>
|
||||||
|
</Stack>
|
||||||
|
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
||||||
|
<Typography variant='subtitle2' sx={style1} gutterBottom>Billing Number</Typography>
|
||||||
|
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.billing_no ? requestLog?.billing_no : '-'}</Typography>
|
||||||
|
</Stack>
|
||||||
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
||||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Provider</Typography>
|
<Typography variant='subtitle2' sx={style1} gutterBottom>Provider</Typography>
|
||||||
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.provider}</Typography>
|
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.provider}</Typography>
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ export type DetailFinalLogType = {
|
|||||||
id : number,
|
id : number,
|
||||||
code : string,
|
code : string,
|
||||||
member_id : string,
|
member_id : string,
|
||||||
|
invoice_no : string,
|
||||||
|
billing_no : string,
|
||||||
provider : string,
|
provider : string,
|
||||||
policy_number : string,
|
policy_number : string,
|
||||||
name : string|any,
|
name : string|any,
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { paramCase } from 'change-case';
|
||||||
|
import { useParams, useLocation } from 'react-router-dom';
|
||||||
|
// @mui
|
||||||
|
import { Container, Stack } from '@mui/material';
|
||||||
|
import useSettings from '../../../hooks/useSettings';
|
||||||
|
import Page from '../../../components/Page';
|
||||||
|
import Form from './Form';
|
||||||
|
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
|
||||||
|
import axios from '../../../utils/axios';
|
||||||
|
import { Practitioner } from '../../../@types/doctor';
|
||||||
|
import ButtonBack from '../../../components/ButtonBack';
|
||||||
|
|
||||||
|
export default function Create() {
|
||||||
|
const { themeStretch } = useSettings();
|
||||||
|
const { id } = useParams();
|
||||||
|
|
||||||
|
const isEdit = id ? true : false;
|
||||||
|
|
||||||
|
const [currentPractitioner, setCurrentPractitioner] = useState<Practitioner>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEdit) {
|
||||||
|
axios.get('/doctors/' + id).then((res) => {
|
||||||
|
setCurrentPractitioner(res.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page title="Membership: Create a new Dokter">
|
||||||
|
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||||
|
<Stack direction="row" alignItems="center">
|
||||||
|
{/* <ButtonBack /> */}
|
||||||
|
<HeaderBreadcrumbs
|
||||||
|
heading={!isEdit ? 'Manage a new Dokter' : 'Manage Dokter'}
|
||||||
|
links={[
|
||||||
|
{ name: 'Master', href: '/master' },
|
||||||
|
{
|
||||||
|
name: 'Doctors',
|
||||||
|
href: '/master/doctors',
|
||||||
|
},
|
||||||
|
{ name: !isEdit ? 'Create' : currentPractitioner?.name ?? '' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Form
|
||||||
|
// isSubmitting={isSubmitting}
|
||||||
|
isEdit={isEdit}
|
||||||
|
currentPractitioner={currentPractitioner}
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// const pageTitle = 'Create Data Dokter';
|
||||||
|
// return (
|
||||||
|
// <Page title={pageTitle}>
|
||||||
|
// <Container maxWidth={themeStretch ? false : 'xl'}>
|
||||||
|
// <HeaderBreadcrumbs
|
||||||
|
// heading={pageTitle}
|
||||||
|
// links={[
|
||||||
|
// {
|
||||||
|
// name: 'Master',
|
||||||
|
// href: '/master',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Dokter',
|
||||||
|
// href: '/master/organizations/',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Create',
|
||||||
|
// href: '/master/organizations/create/',
|
||||||
|
// },
|
||||||
|
// ]}
|
||||||
|
// />
|
||||||
|
|
||||||
|
// <Grid container spacing={2}>
|
||||||
|
// <Grid item xs={12}>
|
||||||
|
// <Card sx={{ p: 2 }}>
|
||||||
|
// <Form
|
||||||
|
// isSubmitting={isSubmitting}
|
||||||
|
// isEdit={isEdit}
|
||||||
|
// currentOrganizations={currentOrganizations}
|
||||||
|
// />
|
||||||
|
// </Card>
|
||||||
|
// </Grid>
|
||||||
|
// </Grid>
|
||||||
|
// </Container>
|
||||||
|
// </Page>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
260
frontend/dashboard/src/pages/EPrescription/Livechat/Form.tsx
Normal file
260
frontend/dashboard/src/pages/EPrescription/Livechat/Form.tsx
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
import * as Yup from 'yup';
|
||||||
|
import { useSnackbar } from 'notistack';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
|
||||||
|
import Select, { SelectChangeEvent } from '@mui/material/Select';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
// form
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
// @mui
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
|
import { LoadingButton } from '@mui/lab';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
|
ButtonGroup,
|
||||||
|
Card,
|
||||||
|
FormHelperText,
|
||||||
|
Grid,
|
||||||
|
Stack,
|
||||||
|
Typography,
|
||||||
|
TextField,
|
||||||
|
Chip,
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import {
|
||||||
|
FormProvider,
|
||||||
|
RHFTextField,
|
||||||
|
RHFRadioGroup,
|
||||||
|
RHFUploadAvatar,
|
||||||
|
RHFSwitch,
|
||||||
|
RHFEditor,
|
||||||
|
RHFDatepicker,
|
||||||
|
RHFMultiCheckbox,
|
||||||
|
RHFCheckbox,
|
||||||
|
RHFCustomMultiCheckbox,
|
||||||
|
} from '../../../components/hook-form';
|
||||||
|
import axios from '../../../utils/axios';
|
||||||
|
import { fCurrency } from '../../../utils/formatNumber';
|
||||||
|
import { Practitioner } from '../../../@types/doctor';
|
||||||
|
|
||||||
|
import { Label, Rowing } from '@mui/icons-material';
|
||||||
|
|
||||||
|
const LabelStyle = styled(Typography)(({ theme }) => ({
|
||||||
|
...theme.typography.subtitle2,
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
marginBottom: theme.spacing(1),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const HeaderStyle = styled('header')(({ theme }) => ({
|
||||||
|
paddingBottom: theme.spacing(5),
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Title = styled(Typography)(({ theme }) => ({
|
||||||
|
...theme.typography.h4,
|
||||||
|
boxShadow: 'none',
|
||||||
|
// paddingBottom: theme.spacing(3),
|
||||||
|
fontWeight: 700,
|
||||||
|
color: '#005B7F',
|
||||||
|
}));
|
||||||
|
|
||||||
|
interface FormValuesProps extends Partial<Practitioner> {
|
||||||
|
taxes: boolean;
|
||||||
|
inStock: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isEdit: boolean;
|
||||||
|
currentPractitioner?: Practitioner;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Span = styled(Typography)(({ theme }) => ({
|
||||||
|
boxShadow: 'none',
|
||||||
|
paddingBottom: theme.spacing(1),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Text = styled(Typography)(({ theme }) => ({
|
||||||
|
boxShadow: 'none',
|
||||||
|
paddingBottom: theme.spacing(3),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function PractitionerForm({ isEdit, currentPractitioner }: Props) {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [practitioner_group, setPractitionerGroups] = useState([]);
|
||||||
|
|
||||||
|
// const [ errors, setErrors ] = useState<{ [key: string]: string }>({});
|
||||||
|
|
||||||
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
|
||||||
|
const NewCorporateSchema = Yup.object().shape({
|
||||||
|
name: Yup.string().required('Name is required'),
|
||||||
|
// file: Yup.boolean().required('Corporate Status is required'),
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultValues = useMemo(
|
||||||
|
() => ({
|
||||||
|
id: currentPractitioner?.id,
|
||||||
|
name: currentPractitioner?.name || '',
|
||||||
|
address: currentPractitioner?.address || '',
|
||||||
|
birth_date: currentPractitioner?.birth_date || '',
|
||||||
|
gender: currentPractitioner?.gender || '',
|
||||||
|
description: currentPractitioner?.description || '',
|
||||||
|
birth_place: currentPractitioner?.birth_place || '',
|
||||||
|
active: currentPractitioner?.active === 1 ? true : false,
|
||||||
|
avatar_url: currentPractitioner?.avatar_url || '',
|
||||||
|
doctor_id: currentPractitioner?.doctor_id || '',
|
||||||
|
organizations: currentPractitioner?.organizations || [],
|
||||||
|
specialities: currentPractitioner?.specialities || [],
|
||||||
|
}),
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
[currentPractitioner]
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('defaultValues', defaultValues);
|
||||||
|
|
||||||
|
function StatusLabel({ value }: { value: boolean }) {
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
label={value ? 'Aktif' : 'Tidak Aktif'}
|
||||||
|
size="medium"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: value ? 'rgba(84, 214, 44, 0.16)' : 'rgba(255, 72, 66, 0.16)',
|
||||||
|
color: value ? '#229A16' : '#B72136',
|
||||||
|
padding: '1 8 1 8 px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
fontSize: '12px',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const methods = useForm<FormValuesProps>({
|
||||||
|
resolver: yupResolver(NewCorporateSchema),
|
||||||
|
defaultValues,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
reset,
|
||||||
|
watch,
|
||||||
|
control,
|
||||||
|
setValue,
|
||||||
|
getValues,
|
||||||
|
setError,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { isSubmitting },
|
||||||
|
} = methods;
|
||||||
|
|
||||||
|
const values = watch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEdit && currentPractitioner) {
|
||||||
|
reset(defaultValues);
|
||||||
|
}
|
||||||
|
if (!isEdit) {
|
||||||
|
reset(defaultValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [isEdit, currentPractitioner]);
|
||||||
|
|
||||||
|
const handleActivate = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setValue('active', event.target.checked);
|
||||||
|
|
||||||
|
console.log('event.target.checked', event.target.checked);
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('active', event.target.checked ? '1' : '0');
|
||||||
|
formData.append('_method', 'PUT');
|
||||||
|
axios.post('/doctors/' + currentPractitioner?.id ?? '', formData);
|
||||||
|
|
||||||
|
enqueueSnackbar('active Updated Successfully!', { variant: 'success' });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormProvider methods={methods}>
|
||||||
|
<Stack spacing={3}>
|
||||||
|
<Box sx={{ width: '100%' }}>
|
||||||
|
{/* <Stack spacing={3}> */}
|
||||||
|
<Card sx={{ p: 5 }}>
|
||||||
|
<HeaderStyle>
|
||||||
|
<Grid item xs={6} md={6}>
|
||||||
|
<Title>Data Dokter</Title>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6} md={6}>
|
||||||
|
{/* <Typography>Status Rumah Sakit</Typography> */}
|
||||||
|
<RHFSwitch name="active" label="" onClick={handleActivate} />
|
||||||
|
<StatusLabel value={values.active} />
|
||||||
|
</Grid>
|
||||||
|
</HeaderStyle>
|
||||||
|
<Title variant="h5">Informasi Umum</Title>
|
||||||
|
<Avatar
|
||||||
|
alt="Remy Sharp"
|
||||||
|
src={currentPractitioner?.avatar_url}
|
||||||
|
sx={{ width: 120, height: 120, marginBottom: 2 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||||
|
<Grid item xs={7}>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Nama Dokter</Span>
|
||||||
|
<Text>{currentPractitioner?.name ? currentPractitioner?.name : '-'}</Text>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>No Telp</Span>
|
||||||
|
<Text>{currentPractitioner?.phone ? currentPractitioner?.phone : '-'}</Text>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Tempat Lahir</Span>
|
||||||
|
<Text>
|
||||||
|
{currentPractitioner?.birth_place ? currentPractitioner?.birth_place : '-'}
|
||||||
|
</Text>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Alamat</Span>
|
||||||
|
<Text>{currentPractitioner?.address ? currentPractitioner?.address : '-'}</Text>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={5} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Jenis Kelamin</Span>
|
||||||
|
<Text>{currentPractitioner?.gender ? currentPractitioner?.gender : '-'}</Text>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Email</Span>
|
||||||
|
<Text>{currentPractitioner?.email ? currentPractitioner?.email : '-'}</Text>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Tanggal Lahir</Span>
|
||||||
|
<Text>
|
||||||
|
{currentPractitioner?.birth_date ? currentPractitioner?.birth_date : '-'}
|
||||||
|
</Text>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Card>
|
||||||
|
<Card sx={{ p: 5, marginTop: 2 }}>
|
||||||
|
<Title variant="h5">Tempat Praktik</Title>
|
||||||
|
{currentPractitioner?.organizations?.map((item, index) => (
|
||||||
|
<Box key={index} sx={{ mt: 3 }}>
|
||||||
|
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||||
|
<Grid item xs={7}>
|
||||||
|
<Text>{item.name}</Text>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Card>
|
||||||
|
<Card sx={{ p: 5, marginTop: 2 }}>
|
||||||
|
<Title variant="h5">Spesialisasi</Title>
|
||||||
|
{currentPractitioner?.specialities?.map((item, index) => (
|
||||||
|
<Box key={index} sx={{ mt: 3 }}>
|
||||||
|
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||||
|
<Grid item xs={7}>
|
||||||
|
<Text>{item.name}</Text>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Card>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</FormProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Card, Grid, Container } from '@mui/material';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
|
||||||
|
import Page from '../../../components/Page';
|
||||||
|
import useSettings from '../../../hooks/useSettings';
|
||||||
|
import List from './List';
|
||||||
|
|
||||||
|
export default function Doctor() {
|
||||||
|
const { themeStretch } = useSettings();
|
||||||
|
|
||||||
|
const { id } = useParams();
|
||||||
|
|
||||||
|
const pageTitle = 'E-Prescription';
|
||||||
|
return (
|
||||||
|
<Page title={pageTitle}>
|
||||||
|
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||||
|
<HeaderBreadcrumbs
|
||||||
|
heading={pageTitle}
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
name: ' E-Prescription',
|
||||||
|
href: 'e-prescription/live-chat',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<List />
|
||||||
|
</Container>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
573
frontend/dashboard/src/pages/EPrescription/Livechat/List.tsx
Normal file
573
frontend/dashboard/src/pages/EPrescription/Livechat/List.tsx
Normal file
@@ -0,0 +1,573 @@
|
|||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Collapse,
|
||||||
|
Paper,
|
||||||
|
Select,
|
||||||
|
SelectChangeEvent,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
TextField,
|
||||||
|
Typography,
|
||||||
|
Stack,
|
||||||
|
ButtonGroup,
|
||||||
|
Grid,
|
||||||
|
Chip,
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogContentText,
|
||||||
|
DialogActions,
|
||||||
|
FormControl,
|
||||||
|
Autocomplete,
|
||||||
|
InputAdornment,
|
||||||
|
IconButton,
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Link,
|
||||||
|
NavLink as RouterLink,
|
||||||
|
useSearchParams,
|
||||||
|
useNavigate,
|
||||||
|
useParams,
|
||||||
|
} from 'react-router-dom';
|
||||||
|
// hooks
|
||||||
|
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||||
|
import useSettings from '../../../hooks/useSettings';
|
||||||
|
// components
|
||||||
|
import axios from '../../../utils/axios';
|
||||||
|
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||||
|
import { Icd } from '../../../@types/diagnosis';
|
||||||
|
import BasePagination from '../../../components/BasePagination';
|
||||||
|
import { Practitioner } from '../../../@types/doctor';
|
||||||
|
import CreateIcon from '@mui/icons-material/Create';
|
||||||
|
import { Props } from '../../../components/editor/index';
|
||||||
|
import { red } from '@mui/material/colors';
|
||||||
|
import { margin, padding } from '@mui/system';
|
||||||
|
import { enqueueSnackbar } from 'notistack';
|
||||||
|
import { Controller } from 'react-hook-form';
|
||||||
|
|
||||||
|
import SvgIconStyle from '../../../components/SvgIconStyle';
|
||||||
|
import { GridSearchIcon } from '@mui/x-data-grid';
|
||||||
|
import { Add, Search } from '@mui/icons-material';
|
||||||
|
import { Icon } from '@iconify/react';
|
||||||
|
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||||
|
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||||
|
import { RHFDatepicker } from '@/components/hook-form';
|
||||||
|
import { DesktopDatePicker, LocalizationProvider } from '@mui/x-date-pickers';
|
||||||
|
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
||||||
|
import { fDateOnly } from '@/utils/formatTime';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
export default function List() {
|
||||||
|
// Generate the every row of the table
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { organization_id } = useParams();
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
|
const [searchParamsOrganizations, setSearchParamsOrganizations] = useSearchParams();
|
||||||
|
const [searchParamsSpecialities, setSearchParamsSpecialities] = useSearchParams();
|
||||||
|
const [searchParamsFilter, setSearchParamsFilter] = useSearchParams();
|
||||||
|
|
||||||
|
function Filter(props: any) {
|
||||||
|
// SEARCH
|
||||||
|
const searchInput = useRef<HTMLInputElement>(null);
|
||||||
|
const [searchText, setSearchText] = useState('');
|
||||||
|
|
||||||
|
//handle search
|
||||||
|
const handleSearchChange = (event: any) => {
|
||||||
|
const newSearchText = event.target.value ?? '';
|
||||||
|
setSearchText(newSearchText);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearchSubmit = (event: any) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
props.onSearch(searchText);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Trigger First Search
|
||||||
|
setSearchText(searchParams.get('search') ?? '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const item = [
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
value: '',
|
||||||
|
name: 'Semua',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form style={{ width: '100%' }}>
|
||||||
|
<Grid container spacing={2} sx={{ justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
|
<Grid item xs={12} md={6}>
|
||||||
|
<TextField
|
||||||
|
id="search-input"
|
||||||
|
ref={searchInput}
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
onChange={handleSearchChange}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
handleSearchSubmit(event);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
value={searchText}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<Search />
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
placeholder: 'Search',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={2}>
|
||||||
|
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||||
|
<DesktopDatePicker
|
||||||
|
value={searchParams.get('startDate')}
|
||||||
|
inputFormat="dd/MM/yyyy"
|
||||||
|
onChange={(value) => {
|
||||||
|
try {
|
||||||
|
if (value && !!Date.parse(value)) {
|
||||||
|
const date = value ? fDateOnly(value) : '';
|
||||||
|
var entries = [...searchParams.entries(), ['startDate', date ?? '']];
|
||||||
|
if (!searchParams.get('endDate')) {
|
||||||
|
entries = [...entries, ['endDate', date ?? '']];
|
||||||
|
}
|
||||||
|
const filter = Object.fromEntries(entries);
|
||||||
|
|
||||||
|
setSearchParams(filter);
|
||||||
|
loadDataTableData(filter);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}}
|
||||||
|
renderInput={(params) => <TextField {...params} fullWidth label="Start" />}
|
||||||
|
/>
|
||||||
|
</LocalizationProvider>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={2}>
|
||||||
|
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||||
|
<DesktopDatePicker
|
||||||
|
value={searchParams.get('endDate')}
|
||||||
|
inputFormat="dd/MM/yyyy"
|
||||||
|
onChange={(value) => {
|
||||||
|
try {
|
||||||
|
if (value && !!Date.parse(value)) {
|
||||||
|
const date = fDateOnly(value);
|
||||||
|
var entries = [...searchParams.entries(), ['endDate', date ?? '']];
|
||||||
|
if (!searchParams.get('startDate')) {
|
||||||
|
entries = [...entries, ['startDate', date ?? '']];
|
||||||
|
}
|
||||||
|
const filter = Object.fromEntries(entries);
|
||||||
|
|
||||||
|
setSearchParams(filter);
|
||||||
|
loadDataTableData(filter);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
fullWidth
|
||||||
|
label="End"
|
||||||
|
// error={!!error}
|
||||||
|
// helperText={error?.message}
|
||||||
|
// {...other}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</LocalizationProvider>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={2}>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
startIcon={<Add />}
|
||||||
|
sx={{ p: 1.8 }}
|
||||||
|
onClick={exportExcel}
|
||||||
|
>
|
||||||
|
Export
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function FilterForm(props: any) {
|
||||||
|
// IMPORT
|
||||||
|
return (
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={2}
|
||||||
|
sx={{ p: 2, justifyContent: 'space-between', alignItems: 'center' }}
|
||||||
|
>
|
||||||
|
<Grid item xs={12} md={12} lg={12}>
|
||||||
|
<Filter onSearch={applyItems} />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createData(doctor: Practitioner): Practitioner {
|
||||||
|
return {
|
||||||
|
...doctor,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||||
|
const { row } = props;
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
|
const [openDialog, setOpenDialog] = React.useState(false);
|
||||||
|
|
||||||
|
const handleDelete = (model: any) => {
|
||||||
|
axios
|
||||||
|
.delete(`/doctors/${row.id}`)
|
||||||
|
.then((res) => {
|
||||||
|
setDataTableData({
|
||||||
|
...dataTableData,
|
||||||
|
data: dataTableData.data.filter((model) => model.id != row.id),
|
||||||
|
});
|
||||||
|
enqueueSnackbar('Data berhasil dihapus', { variant: 'success' });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
enqueueSnackbar(
|
||||||
|
error.response.data.message ?? error.message ?? 'Failed Processing Request',
|
||||||
|
{ variant: 'error' }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>
|
||||||
|
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||||
|
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="left">{row.date_created ? row.date_created : '-'}</TableCell>
|
||||||
|
<TableCell align="left">{row.time_request ? row.time_request : '-'}</TableCell>
|
||||||
|
<TableCell align="left">{row.health_care ? row.health_care : '-'}</TableCell>
|
||||||
|
<TableCell align="left">{row.doctor_name ? row.doctor_name : '-'}</TableCell>
|
||||||
|
<TableCell align="left">{row.speciality ? row.speciality : '-'}</TableCell>
|
||||||
|
<TableCell align="left">{row.pasien_name ? row.pasien_name : '-'}</TableCell>
|
||||||
|
<TableCell align="left">{row.pasien_phone ? row.pasien_phone : '-'}</TableCell>
|
||||||
|
{/* <TableCell align="left">{row.appointment_media ? row.appointment_media : '-'}</TableCell> */}
|
||||||
|
<TableCell align="left">{row.patient_media ? row.patient_media : '-'}</TableCell>
|
||||||
|
<TableCell align="left">{row.doctor_media ? row.doctor_media : '-'}</TableCell>
|
||||||
|
{/* <TableCell align="left">
|
||||||
|
{row.status_appointment ? row.status_appointment : '-'}
|
||||||
|
</TableCell> */}
|
||||||
|
<TableCell align="left">{row.status_chat ? row.status_chat : '-'}</TableCell>
|
||||||
|
<TableCell align="center">
|
||||||
|
<ButtonGroup variant="text" aria-label="text button group">
|
||||||
|
<Link to={'/e-prescription/live-chat/' + row.id + '/show'}>
|
||||||
|
<Button>
|
||||||
|
<Icon icon="ph:eye-bold" style={{ width: '24px', height: '24px' }} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</ButtonGroup>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
{/* COLLAPSIBLE ROW */}
|
||||||
|
<TableRow>
|
||||||
|
<TableCell
|
||||||
|
style={{ paddingBottom: 0, paddingTop: 0, backgroundColor: 'rgba(244, 246, 248, 0.5)' }}
|
||||||
|
colSpan={6}
|
||||||
|
>
|
||||||
|
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||||
|
<Box sx={{ margin: 1, pb: 2, pl: 4 }}>
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs={12} sx={{ padding: 2 }}>
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
Metode Pembayaran
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
: {row.payment_method ? row.payment_method : '-'}
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={6}>
|
||||||
|
Jenis Benefit
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
: -
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
Durasi
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
: {row.duration ? row.duration : '-'}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
Kode
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
: {row.id ? row.id : '-'}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</Collapse>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
|
||||||
|
{/* END COLLAPSIBLE ROW */}
|
||||||
|
<Dialog
|
||||||
|
open={openDialog}
|
||||||
|
onClose={() => {
|
||||||
|
setOpenDialog(false);
|
||||||
|
}}
|
||||||
|
aria-labelledby="alert-dialog-title"
|
||||||
|
aria-describedby="alert-dialog-description"
|
||||||
|
>
|
||||||
|
<DialogContent sx={{ p: 5 }}>
|
||||||
|
<Icon
|
||||||
|
icon="eva:trash-2-outline"
|
||||||
|
style={{
|
||||||
|
width: '100px',
|
||||||
|
height: '100px',
|
||||||
|
color: '#FF0000',
|
||||||
|
margin: 'auto',
|
||||||
|
display: 'block',
|
||||||
|
marginBottom: '20px',
|
||||||
|
alignContent: 'center',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<DialogContentText sx={{ fontWeight: 'bold', pb: 1 }} id="alert-dialog-title">
|
||||||
|
Apakah anda yakin ingin menghapus
|
||||||
|
</DialogContentText>
|
||||||
|
<Typography sx={{ fontWeight: 'bold' }} id="alert-dialog-title">
|
||||||
|
{row.name}?
|
||||||
|
</Typography>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setOpenDialog(false);
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
Batal
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
handleDelete(row.id);
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
autoFocus
|
||||||
|
>
|
||||||
|
Hapus
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const headStyle = {
|
||||||
|
fontWeight: 'bold',
|
||||||
|
};
|
||||||
|
// Dummy Default Data
|
||||||
|
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||||
|
const [dataTableLastRequest, setDataTableLastRequest] = useState(0);
|
||||||
|
const [dataTableResponseState, setDataTableResponseState] = useState('idle');
|
||||||
|
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>({
|
||||||
|
current_page: 1,
|
||||||
|
data: [],
|
||||||
|
path: '',
|
||||||
|
first_page_url: '',
|
||||||
|
last_page: 1,
|
||||||
|
last_page_url: '',
|
||||||
|
next_page_url: '',
|
||||||
|
prev_page_url: '',
|
||||||
|
per_page: 10,
|
||||||
|
from: 0,
|
||||||
|
to: 0,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
|
const [dataTablePage, setDataTablePage] = useState(5);
|
||||||
|
|
||||||
|
const loadDataTableData = async (appliedFilter: any | null = null) => {
|
||||||
|
setDataTableLoading(true);
|
||||||
|
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||||
|
const response = await axios.get('/prescription', {
|
||||||
|
params: filter,
|
||||||
|
});
|
||||||
|
setDataTableLoading(false);
|
||||||
|
setDataTableData(response.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const exportExcel = async () => {
|
||||||
|
var filter = Object.fromEntries([...searchParams.entries()]);
|
||||||
|
|
||||||
|
await axios
|
||||||
|
.get('live-chat/export', { params: filter })
|
||||||
|
.then((res) => {
|
||||||
|
enqueueSnackbar('Data berhasil di Export', {
|
||||||
|
variant: 'success',
|
||||||
|
anchorOrigin: { horizontal: 'right', vertical: 'top' },
|
||||||
|
});
|
||||||
|
|
||||||
|
document.location.href = res.data.data.file_url;
|
||||||
|
})
|
||||||
|
.catch((err) =>
|
||||||
|
enqueueSnackbar('Data Gagal di Export', {
|
||||||
|
variant: 'error',
|
||||||
|
anchorOrigin: { horizontal: 'right', vertical: 'top' },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// const applyFilter = async (searchFilter: string) => {
|
||||||
|
// await loadDataTableData({ search: searchFilter });
|
||||||
|
// setSearchParams({ search: searchFilter });
|
||||||
|
// };
|
||||||
|
|
||||||
|
const applyItems = async (
|
||||||
|
searchFilter: string,
|
||||||
|
searchFilterOrganization: string,
|
||||||
|
searchFilterSpecialities: string
|
||||||
|
) => {
|
||||||
|
await loadDataTableData({
|
||||||
|
search: searchFilter,
|
||||||
|
organization_id: searchFilterOrganization,
|
||||||
|
speciality_id: searchFilterSpecialities,
|
||||||
|
});
|
||||||
|
setSearchParamsFilter({
|
||||||
|
search: searchFilter,
|
||||||
|
organization_id: searchFilterOrganization,
|
||||||
|
speciality_id: searchFilterSpecialities,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePageChange = (event: ChangeEvent, value: number) => {
|
||||||
|
const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]);
|
||||||
|
loadDataTableData(filter);
|
||||||
|
setSearchParams(filter);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadDataTableData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack>
|
||||||
|
{/* <Ambulace /> */}
|
||||||
|
|
||||||
|
<Card sx={{ marginTop: '30px' }}>
|
||||||
|
<FilterForm sx={{ marginTop: '100px' }} />
|
||||||
|
|
||||||
|
{/* The Main Table */}
|
||||||
|
<TableContainer component={Paper}>
|
||||||
|
<Table>
|
||||||
|
<TableBody>
|
||||||
|
<TableRow>
|
||||||
|
{/* <TableCell colSpan={8} rowSpan={1} align="center" /> */}
|
||||||
|
<TableCell style={headStyle} align="left" />
|
||||||
|
<TableCell style={headStyle} rowSpan={2} align="left">
|
||||||
|
Tanggal
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={headStyle} rowSpan={2} align="left">
|
||||||
|
Waktu
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={headStyle} rowSpan={2} align="left">
|
||||||
|
Faskes
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={headStyle} rowSpan={2} align="left">
|
||||||
|
Nama Dokter
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={headStyle} rowSpan={2} align="left">
|
||||||
|
Spesialisasi
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={headStyle} rowSpan={2} align="left">
|
||||||
|
Nama Pasien
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={headStyle} rowSpan={2} align="left">
|
||||||
|
No Telepon Pasien
|
||||||
|
</TableCell>
|
||||||
|
{/* <TableCell style={headStyle} rowSpan={2} align="left">
|
||||||
|
Appointment Via App/Website
|
||||||
|
</TableCell> */}
|
||||||
|
<TableCell
|
||||||
|
colSpan={2}
|
||||||
|
style={headStyle}
|
||||||
|
align="center"
|
||||||
|
sx={{ borderBottom: '3px solid #d7d7d7' }}
|
||||||
|
>
|
||||||
|
Chat Via App/Website
|
||||||
|
</TableCell>
|
||||||
|
{/* <TableCell style={headStyle} rowSpan={2} align="left">
|
||||||
|
Status Appointment
|
||||||
|
</TableCell> */}
|
||||||
|
<TableCell style={headStyle} rowSpan={2} align="left">
|
||||||
|
Status
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell style={headStyle} align="left" />
|
||||||
|
{/* <TableCell style={headStyle} align="left">
|
||||||
|
Tanggal Booking
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={headStyle} align="left">
|
||||||
|
Tanggal Appointment
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={headStyle} align="left">
|
||||||
|
Faskes
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={headStyle} align="left">
|
||||||
|
Nama Dokter
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={headStyle} align="left">
|
||||||
|
Spesialisasi
|
||||||
|
</TableCell> */}
|
||||||
|
<TableCell style={headStyle} align="left">
|
||||||
|
Pasien
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={headStyle} align="left">
|
||||||
|
Dokter
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
{dataTableIsLoading ? (
|
||||||
|
<TableBody>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={8} align="center">
|
||||||
|
Loading
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
) : dataTableData.data.length == 0 ? (
|
||||||
|
<TableBody>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={8} align="center">
|
||||||
|
No Data
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
) : (
|
||||||
|
<TableBody>
|
||||||
|
{dataTableData.data.map((row) => (
|
||||||
|
<Row key={row.id} row={row} />
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
)}
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
|
||||||
|
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||||
|
</Card>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
53
frontend/dashboard/src/pages/EPrescription/Livechat/Show.tsx
Normal file
53
frontend/dashboard/src/pages/EPrescription/Livechat/Show.tsx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { paramCase } from 'change-case';
|
||||||
|
import { useParams, useLocation } from 'react-router-dom';
|
||||||
|
// @mui
|
||||||
|
import { Container, Stack } from '@mui/material';
|
||||||
|
import useSettings from '../../../hooks/useSettings';
|
||||||
|
import Page from '../../../components/Page';
|
||||||
|
import View from './View';
|
||||||
|
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
|
||||||
|
import axios from '../../../utils/axios';
|
||||||
|
import { Appointment } from '../../../@types/doctor';
|
||||||
|
|
||||||
|
export default function Create() {
|
||||||
|
const { themeStretch } = useSettings();
|
||||||
|
const { id } = useParams();
|
||||||
|
|
||||||
|
const isEdit = id ? true : false;
|
||||||
|
|
||||||
|
const [currentAppointment, setCurrentAppointment] = useState<Appointment>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEdit) {
|
||||||
|
axios.get('/live-chat/' + id).then((res) => {
|
||||||
|
setCurrentAppointment(res.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page title="E-Prescription">
|
||||||
|
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||||
|
<Stack direction="row" alignItems="center">
|
||||||
|
<HeaderBreadcrumbs
|
||||||
|
heading={!isEdit ? 'E-Prescription' : 'E-Prescription'}
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
name: 'E-Prescription',
|
||||||
|
href: 'e-prescription/live-chat',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<View
|
||||||
|
// isSubmitting={isSubmitting}
|
||||||
|
isEdit={isEdit}
|
||||||
|
id={id}
|
||||||
|
currentAppointment={currentAppointment}
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
687
frontend/dashboard/src/pages/EPrescription/Livechat/View.tsx
Normal file
687
frontend/dashboard/src/pages/EPrescription/Livechat/View.tsx
Normal file
@@ -0,0 +1,687 @@
|
|||||||
|
import * as Yup from 'yup';
|
||||||
|
import { useSnackbar } from 'notistack';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
|
||||||
|
import Select, { SelectChangeEvent } from '@mui/material/Select';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
// form
|
||||||
|
import {useFieldArray, useForm } from 'react-hook-form';
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
// @mui
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
|
import { LoadingButton } from '@mui/lab';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Autocomplete,
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
|
ButtonGroup,
|
||||||
|
Card,
|
||||||
|
FormHelperText,
|
||||||
|
Grid,
|
||||||
|
Stack,
|
||||||
|
Typography,
|
||||||
|
TextField,
|
||||||
|
Chip,
|
||||||
|
Badge,
|
||||||
|
Divider,
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import {
|
||||||
|
FormProvider,
|
||||||
|
RHFTextField,
|
||||||
|
RHFRadioGroup,
|
||||||
|
RHFUploadAvatar,
|
||||||
|
RHFSwitch,
|
||||||
|
RHFEditor,
|
||||||
|
RHFDatepicker,
|
||||||
|
RHFMultiCheckbox,
|
||||||
|
RHFCheckbox,
|
||||||
|
RHFCustomMultiCheckbox,
|
||||||
|
} from '../../../components/hook-form';
|
||||||
|
import axios from '../../../utils/axios';
|
||||||
|
import { fCurrency } from '../../../utils/formatNumber';
|
||||||
|
import { Appointment } from '../../../@types/doctor';
|
||||||
|
import RHFTextFieldMoney from "@/components/hook-form/v2/RHFTextFieldMoney";
|
||||||
|
|
||||||
|
import { Label, Rowing, Spa } from '@mui/icons-material';
|
||||||
|
import { border, padding } from '@mui/system';
|
||||||
|
import { IconButton } from '@mui/material';
|
||||||
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
|
import RemoveIcon from '@mui/icons-material/Remove';
|
||||||
|
|
||||||
|
const LabelStyle = styled(Typography)(({ theme }) => ({
|
||||||
|
...theme.typography.subtitle2,
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
marginBottom: theme.spacing(1),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const HeaderStyle = styled('header')(({ theme }) => ({
|
||||||
|
paddingBottom: theme.spacing(5),
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Title = styled(Typography)(({ theme }) => ({
|
||||||
|
...theme.typography.h4,
|
||||||
|
boxShadow: 'none',
|
||||||
|
// paddingBottom: theme.spacing(3),
|
||||||
|
fontWeight: 700,
|
||||||
|
color: '#005B7F',
|
||||||
|
}));
|
||||||
|
|
||||||
|
interface FormValuesProps extends Partial<Appointment> {
|
||||||
|
taxes: boolean;
|
||||||
|
inStock: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isEdit: boolean;
|
||||||
|
id: number;
|
||||||
|
currentAppointment?: Appointment;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Span = styled(Typography)(({ theme }) => ({
|
||||||
|
boxShadow: 'none',
|
||||||
|
paddingBottom: theme.spacing(1),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Text = styled(Typography)(({ theme }) => ({
|
||||||
|
boxShadow: 'none',
|
||||||
|
paddingBottom: theme.spacing(3),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function AppointmentForm({ isEdit, id, currentAppointment }: Props) {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
// const [ errors, setErrors ] = useState<{ [key: string]: string }>({});
|
||||||
|
|
||||||
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
|
||||||
|
const NewCorporateSchema = Yup.object().shape({
|
||||||
|
// name: Yup.string().required('Name is required'),
|
||||||
|
// file: Yup.boolean().required('Corporate Status is required'),
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultValues = useMemo(
|
||||||
|
() => ({
|
||||||
|
id: currentAppointment?.id,
|
||||||
|
name: currentAppointment?.name || '',
|
||||||
|
address: currentAppointment?.address || '',
|
||||||
|
birth_date: currentAppointment?.birth_date || '',
|
||||||
|
gender: currentAppointment?.gender || '',
|
||||||
|
description: currentAppointment?.description || '',
|
||||||
|
birth_place: currentAppointment?.birth_place || '',
|
||||||
|
active: currentAppointment?.active === 1 ? true : false,
|
||||||
|
avatar_url: currentAppointment?.avatar_url || '',
|
||||||
|
doctor_id: currentAppointment?.doctor_id || '',
|
||||||
|
organizations: currentAppointment?.organizations || [],
|
||||||
|
specialities: currentAppointment?.specialities || [],
|
||||||
|
diagnosis: currentAppointment?.diagnosis || '',
|
||||||
|
hospital: currentAppointment?.hospital || null,
|
||||||
|
medicine : currentAppointment?.medicine || [
|
||||||
|
{
|
||||||
|
drug_id: 0,
|
||||||
|
qty: 0,
|
||||||
|
signa: '',
|
||||||
|
unit_id: 0,
|
||||||
|
note: '', // input to database
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
[currentAppointment]
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log()
|
||||||
|
|
||||||
|
const methods = useForm<FormValuesProps>({
|
||||||
|
// resolver: yupResolver(NewCorporateSchema),
|
||||||
|
defaultValues,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {fields, append, remove} = useFieldArray({name: 'medicine',control: methods.control})
|
||||||
|
|
||||||
|
// Autocomplite ICD
|
||||||
|
const [icdOptions, setIcdOptions] = useState([]);
|
||||||
|
useEffect(() => {
|
||||||
|
// Ambil data dari API dan atur opsi ICD
|
||||||
|
axios.get('diagnosis')
|
||||||
|
.then((response) => {
|
||||||
|
setIcdOptions(response.data.data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error fetching ICD options:', error);
|
||||||
|
});
|
||||||
|
}, []); // useEffect dijalankan hanya sekali saat komponen dimount
|
||||||
|
|
||||||
|
// Menggunakan selectedIcdOptions sebagai state untuk nilai default
|
||||||
|
const [selectedIcdOptions, setSelectedIcdOptions] = useState([]);
|
||||||
|
const codes = defaultValues.diagnosis.split(',');
|
||||||
|
useEffect(() => {
|
||||||
|
// Pastikan bahwa icdOptions sudah terisi sebelum memfilter
|
||||||
|
if (icdOptions.length > 0) {
|
||||||
|
const selectedCodes = icdOptions.filter((icd) => {
|
||||||
|
return codes.includes(icd.value);
|
||||||
|
});
|
||||||
|
setSelectedIcdOptions(selectedCodes);
|
||||||
|
// setValue('diagnosis', selectedCodes); // Ini bisa Anda hilangkan jika tidak diperlukan
|
||||||
|
}
|
||||||
|
}, [icdOptions, defaultValues.diagnosis]);
|
||||||
|
|
||||||
|
|
||||||
|
// Autocomplite Rumah Sakit
|
||||||
|
const [hospitalOptions, setHospitalOptions] = useState([]);
|
||||||
|
const [selectedHospitalOption, setSelectedHospitalOption] = useState(null);
|
||||||
|
|
||||||
|
// Ambil data dari API dan atur opsi rumah sakit
|
||||||
|
useEffect(() => {
|
||||||
|
axios.get('hospitals')
|
||||||
|
.then((response) => {
|
||||||
|
setHospitalOptions(response.data.data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error fetching hospital options:', error);
|
||||||
|
});
|
||||||
|
}, []); // useEffect dijalankan hanya sekali saat komponen dimount
|
||||||
|
|
||||||
|
// Set default value saat hospitalOptions berubah
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedId = hospitalOptions.find((hospital) => {
|
||||||
|
|
||||||
|
return hospital.value == defaultValues.hospital
|
||||||
|
});
|
||||||
|
setSelectedHospitalOption(selectedId);
|
||||||
|
setValue('hospital', defaultValues.hospital)
|
||||||
|
|
||||||
|
}, [hospitalOptions, defaultValues]);
|
||||||
|
|
||||||
|
// Autocomplete drugs
|
||||||
|
const [drugOptions, setDrugsOptions] = useState([]);
|
||||||
|
const [selectedDrugsOptions, setSelectedDrugsOptions] = useState({});
|
||||||
|
|
||||||
|
const handleAutocompleteChange = (newValue, index) => {
|
||||||
|
setSelectedDrugsOptions((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
[index]: newValue
|
||||||
|
}));
|
||||||
|
setValue(`medicine.${index}.drug_id`, newValue ? newValue.value : '');
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ambil data dari API dan atur opsi obat
|
||||||
|
useEffect(() => {
|
||||||
|
axios.get('drugs')
|
||||||
|
.then((response) => {
|
||||||
|
const data = response.data.data;
|
||||||
|
// Set nilai default jika data tidak kosong
|
||||||
|
if (data.length > 0) {
|
||||||
|
// Pilih nilai default pertama
|
||||||
|
setSelectedDrugsOptions({ 0: data[0] });
|
||||||
|
setValue('medicine.0.drug_id', data[0] ? data[0].value : '');
|
||||||
|
}
|
||||||
|
setDrugsOptions(data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error fetching drug options:', error);
|
||||||
|
});
|
||||||
|
}, []); // useEffect dijalankan hanya sekali saat komponen dimount
|
||||||
|
|
||||||
|
// Autocomplete unit
|
||||||
|
const [unitOptions, setUnitsOptions] = useState([]);
|
||||||
|
const [selectedUnitsOptions, setSelectedUnitsOptions] = useState({});
|
||||||
|
|
||||||
|
// Ambil data dari API dan atur opsi satuan
|
||||||
|
useEffect(() => {
|
||||||
|
axios.get('units')
|
||||||
|
.then((response) => {
|
||||||
|
const data = response.data.data;
|
||||||
|
// Set nilai default jika data tidak kosong
|
||||||
|
if (data.length > 0) {
|
||||||
|
// Pilih nilai default pertama
|
||||||
|
setSelectedUnitsOptions({ 0: data[0] });
|
||||||
|
setValue('medicine.0.unit_id', data[0] ? data[0].value : '');
|
||||||
|
}
|
||||||
|
setUnitsOptions(data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error fetching unit options:', error);
|
||||||
|
});
|
||||||
|
}, []); // useEffect dijalankan hanya sekali saat komponen dimount
|
||||||
|
|
||||||
|
const handleAutocompleteChangeUnit = (newValue, index) => {
|
||||||
|
setSelectedUnitsOptions((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
[index]: newValue
|
||||||
|
}));
|
||||||
|
setValue(`medicine.${index}.unit_id`, newValue ? newValue.value : '');
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (defaultValues.medicine.length > 0) {
|
||||||
|
defaultValues.medicine.forEach((med, index) => {
|
||||||
|
const selectedDrugId = drugOptions.find((drug) => drug.value === med.drug_id);
|
||||||
|
handleAutocompleteChange(selectedDrugId, index);
|
||||||
|
|
||||||
|
const selectedUnitId = unitOptions.find((unit) => unit.value === med.unit_id);
|
||||||
|
handleAutocompleteChangeUnit(selectedUnitId, index);
|
||||||
|
|
||||||
|
// Lakukan tindakan lainnya sesuai kebutuhan Anda
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('Medicine is empty');
|
||||||
|
}
|
||||||
|
}, [defaultValues.medicine]);
|
||||||
|
|
||||||
|
|
||||||
|
const {
|
||||||
|
reset,
|
||||||
|
watch,
|
||||||
|
control,
|
||||||
|
setValue,
|
||||||
|
getValues,
|
||||||
|
setError,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { isSubmitting },
|
||||||
|
} = methods;
|
||||||
|
|
||||||
|
const values = watch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEdit && currentAppointment) {
|
||||||
|
reset(defaultValues);
|
||||||
|
}
|
||||||
|
if (!isEdit) {
|
||||||
|
reset(defaultValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [isEdit, currentAppointment]);
|
||||||
|
|
||||||
|
const onSubmit = async (data: FormValuesProps) => {
|
||||||
|
try {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('id', data.id);
|
||||||
|
formData.append('diagnosis', data.diagnosis);
|
||||||
|
formData.append('hospital', data.hospital);
|
||||||
|
|
||||||
|
// Iterasi melalui setiap objek dalam array medicine dan menambahkannya ke FormData
|
||||||
|
data.medicine.forEach((medicineObj, index) => {
|
||||||
|
// Anda dapat menambahkan setiap properti dari objek medicine ke FormData
|
||||||
|
formData.append(`medicine[${index}][drug_id]`, medicineObj.drug_id);
|
||||||
|
formData.append(`medicine[${index}][qty]`, medicineObj.qty);
|
||||||
|
formData.append(`medicine[${index}][unit_id]`, medicineObj.unit_id);
|
||||||
|
formData.append(`medicine[${index}][signa]`, medicineObj.signa);
|
||||||
|
formData.append(`medicine[${index}][note]`, medicineObj.note);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const response = await axios.post('/prescription', formData);
|
||||||
|
reset();
|
||||||
|
enqueueSnackbar('Berhasil menambahkan resep', {
|
||||||
|
variant: 'success',
|
||||||
|
});
|
||||||
|
navigate('/e-prescription/live-chat');
|
||||||
|
} catch (error: any) {
|
||||||
|
console.log(error, 'submit')
|
||||||
|
enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const ascent = document?.querySelector('ascent');
|
||||||
|
if (ascent != null) {
|
||||||
|
ascent.innerHTML = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDownloadEPrescription = (id: number) => {
|
||||||
|
axios
|
||||||
|
.get(`prescription-download/${id}`, {
|
||||||
|
responseType: 'blob',
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
window.open(URL.createObjectURL(response.data));
|
||||||
|
})
|
||||||
|
.catch((response) => {
|
||||||
|
enqueueSnackbar(response.message, { variant: 'error' });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<Stack spacing={3}>
|
||||||
|
<Box sx={{ width: '100%' }}>
|
||||||
|
{/* <Stack spacing={3}> */}
|
||||||
|
<Card sx={{ p: 5 }}>
|
||||||
|
<HeaderStyle>
|
||||||
|
<Grid item xs={6} md={6}>
|
||||||
|
<Stack
|
||||||
|
direction="row"
|
||||||
|
divider={<Divider orientation="vertical" flexItem />}
|
||||||
|
spacing={2}
|
||||||
|
>
|
||||||
|
<Title>Data Live Chat</Title>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
</HeaderStyle>
|
||||||
|
|
||||||
|
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Stack direction="row" spacing={2}>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Stack direction="row" spacing={2} alignItems="center">
|
||||||
|
<Span style={{ fontWeight: 'bold', paddingBottom: '0px' }}>
|
||||||
|
Status Appointment :
|
||||||
|
</Span>
|
||||||
|
<Chip
|
||||||
|
label={
|
||||||
|
currentAppointment?.status_appointment
|
||||||
|
? currentAppointment?.status_appointment
|
||||||
|
: '-'
|
||||||
|
}
|
||||||
|
variant="outlined"
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Stack direction="row" spacing={2} alignItems="center">
|
||||||
|
<Span style={{ fontWeight: 'bold', paddingBottom: '0px' }}>
|
||||||
|
Status Chat :
|
||||||
|
</Span>
|
||||||
|
<Chip
|
||||||
|
label={
|
||||||
|
currentAppointment?.status_chat ? currentAppointment?.status_chat : '-'
|
||||||
|
}
|
||||||
|
variant="outlined"
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sx={{ marginTop: '20px' }}>
|
||||||
|
<Stack direction="row" spacing={2}>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Stack direction="row" spacing={2}>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Tanggal Booking :</Span>
|
||||||
|
<Text>
|
||||||
|
{currentAppointment?.date_created ? currentAppointment?.date_created : '-'}
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Stack direction="row" spacing={2}>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Tanggal Appointment :</Span>
|
||||||
|
<Text>
|
||||||
|
{currentAppointment?.date_appointment
|
||||||
|
? currentAppointment?.date_appointment
|
||||||
|
: '-'}
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Nama Dokter</Span>
|
||||||
|
<Text>
|
||||||
|
{currentAppointment?.doctor_name ? currentAppointment?.doctor_name : '-'}
|
||||||
|
</Text>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Faskes</Span>
|
||||||
|
<Text>
|
||||||
|
{currentAppointment?.health_care ? currentAppointment?.health_care : '-'}
|
||||||
|
</Text>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Durasi</Span>
|
||||||
|
<Text>{currentAppointment?.duration ? currentAppointment?.duration : '-'}</Text>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Spesialis</Span>
|
||||||
|
<Text>{currentAppointment?.speciality ? currentAppointment?.speciality : '-'}</Text>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Appointment Via Web/App</Span>
|
||||||
|
<Text>
|
||||||
|
{currentAppointment?.appointment_media
|
||||||
|
? currentAppointment?.appointment_media
|
||||||
|
: '-'}
|
||||||
|
</Text>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Card>
|
||||||
|
<Card sx={{ mt: 5, p: 5 }}>
|
||||||
|
<HeaderStyle>
|
||||||
|
<Grid item xs={6} md={6}>
|
||||||
|
<Title>Data Pembayaran</Title>
|
||||||
|
</Grid>
|
||||||
|
</HeaderStyle>
|
||||||
|
|
||||||
|
{currentAppointment?.payment_detail !== null ? (
|
||||||
|
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Metode Pembayaran</Span>
|
||||||
|
<Text>
|
||||||
|
{currentAppointment?.payment_method ? currentAppointment?.payment_method : '-'}
|
||||||
|
</Text>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Harga</Span>
|
||||||
|
<Text>
|
||||||
|
{currentAppointment?.payment_detail?.gross_amount
|
||||||
|
? currentAppointment?.payment_detail?.gross_amount
|
||||||
|
: '-'}
|
||||||
|
</Text>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Mata Uang</Span>
|
||||||
|
<Text>
|
||||||
|
{currentAppointment?.payment_detail?.currency
|
||||||
|
? currentAppointment?.payment_detail?.currency
|
||||||
|
: '-'}
|
||||||
|
</Text>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Tipe Pembayaran</Span>
|
||||||
|
<Text>
|
||||||
|
{currentAppointment?.payment_detail?.payment_type
|
||||||
|
? currentAppointment?.payment_detail?.payment_type
|
||||||
|
: '-'}
|
||||||
|
</Text>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Waktu Transaksi</Span>
|
||||||
|
<Text>
|
||||||
|
{currentAppointment?.payment_detail?.transaction_time
|
||||||
|
? currentAppointment?.payment_detail?.transaction_time
|
||||||
|
: '-'}
|
||||||
|
</Text>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Status</Span>
|
||||||
|
<Text>
|
||||||
|
{currentAppointment?.payment_detail?.status_message
|
||||||
|
? currentAppointment?.payment_detail?.status_message
|
||||||
|
: '-'}
|
||||||
|
</Text>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
) : (
|
||||||
|
<Span>Belum ada pembayaran</Span>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card sx={{ mt: 5, p: 5 }}>
|
||||||
|
<HeaderStyle>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
|
<Title>E-Prescription</Title>
|
||||||
|
</Grid>
|
||||||
|
</HeaderStyle>
|
||||||
|
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||||
|
|
||||||
|
<Grid item xs={12} columnSpacing={{ xs: 1, sm: 2, md: 3 }} sx={{marginBottom: 4}}>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Diagnosa</Span>
|
||||||
|
<Autocomplete
|
||||||
|
multiple
|
||||||
|
options={icdOptions}
|
||||||
|
getOptionLabel={(option) => option.label}
|
||||||
|
fullWidth
|
||||||
|
value={selectedIcdOptions}
|
||||||
|
onChange={(e, newValues) => {
|
||||||
|
const selectedCodes = newValues.map((value) => value.value);
|
||||||
|
setValue('diagnosis', selectedCodes);
|
||||||
|
setSelectedIcdOptions(newValues);
|
||||||
|
}}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
label="Diagnosis ICD - X"
|
||||||
|
variant="outlined"
|
||||||
|
// required
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* <Grid item xs={12} columnSpacing={{ xs: 1, sm: 2, md: 3 }} sx={{marginBottom: 4}}>
|
||||||
|
<Span style={{ fontWeight: 'bold' }}>Rumah Sakit</Span>
|
||||||
|
<Autocomplete
|
||||||
|
options={hospitalOptions}
|
||||||
|
getOptionLabel={(option) => option.label}
|
||||||
|
fullWidth
|
||||||
|
value={selectedHospitalOption}
|
||||||
|
onChange={(e, newValue) => {
|
||||||
|
setSelectedHospitalOption(newValue);
|
||||||
|
setValue('hospital', newValue ? newValue.value : ''); // Simpan nilai rumah sakit
|
||||||
|
}}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
label="Rumah Sakit"
|
||||||
|
variant="outlined"
|
||||||
|
// required
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</Grid> */}
|
||||||
|
|
||||||
|
<Grid item xs={12} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||||
|
<Stack direction="row" alignItems="center" sx={{marginBottom: 4}}>
|
||||||
|
<Typography variant='subtitle1' gutterBottom>Obat</Typography>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12}>
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<Grid container spacing={2} key={index} sx={{ marginBottom: '15px' }}>
|
||||||
|
<Grid item xs={3}>
|
||||||
|
<Autocomplete
|
||||||
|
options={drugOptions}
|
||||||
|
getOptionLabel={(option) => option.label}
|
||||||
|
fullWidth
|
||||||
|
value={selectedDrugsOptions[index] || null}
|
||||||
|
onChange={(e, newValue) => handleAutocompleteChange(newValue, index)}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
label="Drugs"
|
||||||
|
variant="outlined"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={1}>
|
||||||
|
<RHFTextField
|
||||||
|
id={`qty_${index}`}
|
||||||
|
name={`medicine.${index}.qty`}
|
||||||
|
label="Qty"
|
||||||
|
required
|
||||||
|
type="number"
|
||||||
|
placeholder="Qty"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={2}>
|
||||||
|
<Autocomplete
|
||||||
|
options={unitOptions}
|
||||||
|
getOptionLabel={(option) => option.label}
|
||||||
|
fullWidth
|
||||||
|
value={selectedUnitsOptions[index] || null}
|
||||||
|
onChange={(e, newValue) => handleAutocompleteChangeUnit(newValue, index)}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
label="Units"
|
||||||
|
variant="outlined"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={2}>
|
||||||
|
<RHFTextField
|
||||||
|
id={`signa_${index}`}
|
||||||
|
name={`medicine.${index}.signa`}
|
||||||
|
label="Signa"
|
||||||
|
required
|
||||||
|
placeholder="Signa"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={3}>
|
||||||
|
<RHFTextField
|
||||||
|
id={`note_${index}`}
|
||||||
|
name={`medicine.${index}.note`}
|
||||||
|
label="Note"
|
||||||
|
required
|
||||||
|
placeholder="Note"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
{
|
||||||
|
index === 0 ? (
|
||||||
|
<Grid item xs={1} sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||||
|
<IconButton size='large' color='primary' onClick={() => append({medicine_name: '', medicine_price: 0, request_log_id: 1 })}>
|
||||||
|
<AddIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
|
) : (
|
||||||
|
index == (fields.length-1) ? (
|
||||||
|
<Grid item xs={1} sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||||
|
<IconButton size='large' color='error' onClick={() => remove(index)}>
|
||||||
|
<RemoveIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
|
) : (
|
||||||
|
<Grid item xs={1} sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||||
|
<IconButton size='large' color='primary' onClick={() => append({medicine_name: '', medicine_price: 0, request_log_id: 1 })}>
|
||||||
|
<AddIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={12} sx={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||||
|
<Button
|
||||||
|
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)', marginRight: '10px' }}
|
||||||
|
onClick={() => handleDownloadEPrescription(id)}
|
||||||
|
variant="contained"
|
||||||
|
size="large"
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</Button>
|
||||||
|
<LoadingButton
|
||||||
|
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)' }}
|
||||||
|
type="submit"
|
||||||
|
variant="contained"
|
||||||
|
size="large"
|
||||||
|
loading={isSubmitting}
|
||||||
|
>
|
||||||
|
{!isEdit ? 'Save' : 'Update'}
|
||||||
|
</LoadingButton>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Card>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</FormProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -188,6 +188,8 @@ export default function PractitionerForm({ isEdit, currentPractitioner }: Props)
|
|||||||
// formData.append('active', data.active ? '1' : '0');
|
// formData.append('active', data.active ? '1' : '0');
|
||||||
forms.forEach((form, index) => {
|
forms.forEach((form, index) => {
|
||||||
formData.append(`practices[${index}][organization_id]`, form.organizationId);
|
formData.append(`practices[${index}][organization_id]`, form.organizationId);
|
||||||
|
formData.append(`practices[${index}][period_start]`, form.periodStart);
|
||||||
|
formData.append(`practices[${index}][period_end]`, form.periodEnd);
|
||||||
form.specialities.forEach((speciality, i) => {
|
form.specialities.forEach((speciality, i) => {
|
||||||
formData.append(`practices[${index}][specialities][${i}][speciality_id]`, speciality);
|
formData.append(`practices[${index}][specialities][${i}][speciality_id]`, speciality);
|
||||||
});
|
});
|
||||||
@@ -225,6 +227,7 @@ export default function PractitionerForm({ isEdit, currentPractitioner }: Props)
|
|||||||
|
|
||||||
const [organizations, setOrganizations] = useState<any>([]);
|
const [organizations, setOrganizations] = useState<any>([]);
|
||||||
const [specialities, setSpecialities] = useState<any>([]);
|
const [specialities, setSpecialities] = useState<any>([]);
|
||||||
|
const [price, setPrice] = useState<any>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
axios.get(`/search-organizations`).then((response) => {
|
axios.get(`/search-organizations`).then((response) => {
|
||||||
@@ -281,6 +284,8 @@ export default function PractitionerForm({ isEdit, currentPractitioner }: Props)
|
|||||||
return {
|
return {
|
||||||
organizationId: practice.organization_id,
|
organizationId: practice.organization_id,
|
||||||
specialities: practice.specialities.map((s) => s.speciality_id),
|
specialities: practice.specialities.map((s) => s.speciality_id),
|
||||||
|
periodStart: practice.period_start,
|
||||||
|
periodEnd: practice.period_end,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
setForms(newForms);
|
setForms(newForms);
|
||||||
@@ -289,6 +294,9 @@ export default function PractitionerForm({ isEdit, currentPractitioner }: Props)
|
|||||||
{
|
{
|
||||||
organizationId: '',
|
organizationId: '',
|
||||||
specialities: [],
|
specialities: [],
|
||||||
|
periodStart: '',
|
||||||
|
periodEnd: '',
|
||||||
|
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -333,6 +341,8 @@ export default function PractitionerForm({ isEdit, currentPractitioner }: Props)
|
|||||||
...forms,
|
...forms,
|
||||||
{
|
{
|
||||||
organizationId: '',
|
organizationId: '',
|
||||||
|
periodStart: '',
|
||||||
|
periodEnd: '',
|
||||||
specialities: [],
|
specialities: [],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -397,6 +407,8 @@ export default function PractitionerForm({ isEdit, currentPractitioner }: Props)
|
|||||||
setForms(updatedForms);
|
setForms(updatedForms);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(forms, 'forms')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||||
<Stack spacing={3}>
|
<Stack spacing={3}>
|
||||||
@@ -492,7 +504,6 @@ export default function PractitionerForm({ isEdit, currentPractitioner }: Props)
|
|||||||
value={findValueOrganization(form.organizationId) ?? ''}
|
value={findValueOrganization(form.organizationId) ?? ''}
|
||||||
getOptionLabel={(option) => option.name}
|
getOptionLabel={(option) => option.name}
|
||||||
isOptionEqualToValue={(option, value) => {
|
isOptionEqualToValue={(option, value) => {
|
||||||
console.log(value, option, 'test')
|
|
||||||
return option.value === value.value
|
return option.value === value.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -541,6 +552,23 @@ export default function PractitionerForm({ isEdit, currentPractitioner }: Props)
|
|||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<LabelStyle>Period Start</LabelStyle>
|
||||||
|
<RHFDatepicker
|
||||||
|
name={`period_start`}
|
||||||
|
placeholder="Silahkan Pilih Tanggal Mulai"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<LabelStyle>Period End</LabelStyle>
|
||||||
|
<RHFDatepicker
|
||||||
|
name={`period_end`}
|
||||||
|
placeholder="Silahkan Pilih Tanggal Selesai" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
35
frontend/dashboard/src/pages/Report/FilesProvider/Index.tsx
Normal file
35
frontend/dashboard/src/pages/Report/FilesProvider/Index.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { Card, Grid, Container } from '@mui/material';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
|
||||||
|
import Page from '../../../components/Page';
|
||||||
|
import useSettings from '../../../hooks/useSettings';
|
||||||
|
import List from './List';
|
||||||
|
|
||||||
|
export default function Index() {
|
||||||
|
const { themeStretch } = useSettings();
|
||||||
|
|
||||||
|
const { id } = useParams();
|
||||||
|
|
||||||
|
const pageTitle = 'Files Provider';
|
||||||
|
return (
|
||||||
|
<Page title={pageTitle}>
|
||||||
|
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||||
|
<HeaderBreadcrumbs
|
||||||
|
heading={pageTitle}
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
name: 'Report',
|
||||||
|
href: '#',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Files Provider',
|
||||||
|
href: '/report/files-provider',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<List />
|
||||||
|
</Container>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
999
frontend/dashboard/src/pages/Report/FilesProvider/List.tsx
Normal file
999
frontend/dashboard/src/pages/Report/FilesProvider/List.tsx
Normal file
@@ -0,0 +1,999 @@
|
|||||||
|
// @mui
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Grid,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Collapse,
|
||||||
|
IconButton,
|
||||||
|
MenuItem,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableRow,
|
||||||
|
TextField,
|
||||||
|
Typography,
|
||||||
|
Stack,
|
||||||
|
Menu,
|
||||||
|
ButtonGroup,
|
||||||
|
Tooltip,
|
||||||
|
TableHead,
|
||||||
|
Checkbox,
|
||||||
|
InputAdornment,
|
||||||
|
TableSortLabel,
|
||||||
|
FormControl
|
||||||
|
} from '@mui/material';
|
||||||
|
import { visuallyHidden } from '@mui/utils';
|
||||||
|
|
||||||
|
import { DesktopDatePicker, LocalizationProvider } from '@mui/x-date-pickers';
|
||||||
|
import { fDateOnly } from '@/utils/formatTime';
|
||||||
|
|
||||||
|
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
||||||
|
import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined';
|
||||||
|
import AssessmentIcon from '@mui/icons-material/Assessment';
|
||||||
|
// hooks
|
||||||
|
import React, { ChangeEvent, useEffect, useRef, useState } from 'react';
|
||||||
|
import { Link, Navigate, useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { LoadingButton } from '@mui/lab';
|
||||||
|
// components
|
||||||
|
import axios from '../../../utils/axios';
|
||||||
|
import { LaravelPaginatedData, LaravelPaginatedDataDefault } from '../../../@types/paginated-data';
|
||||||
|
import DataTable from '../../../components/LaravelTable';
|
||||||
|
import { fCurrency } from '../../utils/formatNumber';
|
||||||
|
import EditRoundedIcon from '@mui/icons-material/EditRounded';
|
||||||
|
import { Chip } from '@mui/material';
|
||||||
|
import Iconify from '@/components/Iconify';
|
||||||
|
import { enqueueSnackbar } from 'notistack';
|
||||||
|
import { fDate, fDateTime } from '../../../utils/formatTime';
|
||||||
|
import { Claims } from '@/@types/claims';
|
||||||
|
import Label from '@/components/Label';
|
||||||
|
import { capitalizeFirstLetter } from '@/utils/formatString';
|
||||||
|
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||||
|
import Edit from '@mui/icons-material/Edit';
|
||||||
|
import { Download } from '@mui/icons-material';
|
||||||
|
import { Add, Search } from '@mui/icons-material';
|
||||||
|
import Autocomplete from '@mui/material/Autocomplete';
|
||||||
|
|
||||||
|
import DownloadIcon from '@mui/icons-material/Download';
|
||||||
|
|
||||||
|
import UploadIcon from '@mui/icons-material/Upload';
|
||||||
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
||||||
|
|
||||||
|
import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material';
|
||||||
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
|
|
||||||
|
|
||||||
|
export default function List() {
|
||||||
|
const [selectAll, setSelectAll] = useState(false);
|
||||||
|
const [selectedRows, setSelectedRows] = useState([]);
|
||||||
|
const [providers, setProviders] = useState(null);
|
||||||
|
// const [searchText, setSearchText] = useState('');
|
||||||
|
const [order, setOrder] = useState<Order>('desc');
|
||||||
|
const [orderBy, setOrderBy] = useState('created_at');
|
||||||
|
const [perPage, setPerPage] = useState<number>(0);
|
||||||
|
|
||||||
|
const handleChange = (event, newValue) => {
|
||||||
|
// Jika newValue tidak undefined, atur nilai dataProvider
|
||||||
|
if (newValue !== undefined) {
|
||||||
|
setDataProvider(newValue.service_code);
|
||||||
|
} else {
|
||||||
|
// Jika tidak ada yang dipilih, set dataProvider menjadi string kosong
|
||||||
|
setDataProvider(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Dummy data
|
||||||
|
const dummyServices = [
|
||||||
|
{ service_code: '1', name: 'Service 1' },
|
||||||
|
{ service_code: '2', name: 'Service 2' },
|
||||||
|
{ service_code: '3', name: 'Service 3' },
|
||||||
|
// tambahkan data lain sesuai kebutuhan
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleSelectAll = () => {
|
||||||
|
setSelectAll(!selectAll);
|
||||||
|
if (!selectAll) {
|
||||||
|
const requestedIds = dataTableData.data
|
||||||
|
.filter(row => row.status === 'approved') // Memfilter baris dengan status 'requested'
|
||||||
|
.map(row => row.id); // Mengambil hanya ID dari baris-baris yang memenuhi kondisi
|
||||||
|
setSelectedRows(requestedIds);
|
||||||
|
} else {
|
||||||
|
setSelectedRows([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRowSelect = (id) => {
|
||||||
|
if (selectedRows.includes(id)) {
|
||||||
|
setSelectedRows(selectedRows.filter(rowId => rowId !== id));
|
||||||
|
} else {
|
||||||
|
setSelectedRows([...selectedRows, id]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
|
const [startDate, setStartDate] = useState(null);
|
||||||
|
const [searchText, setSearchText] = useState('');
|
||||||
|
const [endDate, setEndDate] = useState(null);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [dataProvider, setDataProvider] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (startDate !== null || endDate !== null || dataProvider !== null
|
||||||
|
|| order !== null || orderBy !== null || perPage !== 0) {
|
||||||
|
loadDataTableData();
|
||||||
|
getProvider();
|
||||||
|
}
|
||||||
|
}, [startDate, endDate, dataProvider, order, orderBy, perPage]);
|
||||||
|
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [isLoadingImport, setIsLoadingImport] = useState(false);
|
||||||
|
const handleExportReport = async () => {
|
||||||
|
|
||||||
|
|
||||||
|
const year = startDate?.getFullYear();
|
||||||
|
const month = (startDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit
|
||||||
|
const day = startDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit
|
||||||
|
|
||||||
|
const formattedDate = year && month && day ? `${year}-${month}-${day}` : '';
|
||||||
|
|
||||||
|
const year1 = endDate?.getFullYear();
|
||||||
|
const month1 = (endDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit
|
||||||
|
const day1 = endDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit
|
||||||
|
|
||||||
|
const formattedDate1 = year1 && month1 && day1 ? `${year1}-${month1}-${day1}` : '';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var filter = Object.fromEntries([...searchParams.entries()]);
|
||||||
|
setIsLoading(true)
|
||||||
|
await axios
|
||||||
|
.get('/claims/export-claim-management',{
|
||||||
|
params: {
|
||||||
|
search: searchText,
|
||||||
|
start_date: formattedDate ? formattedDate : null,
|
||||||
|
end_date:formattedDate1,
|
||||||
|
provider: dataProvider,
|
||||||
|
order: order,
|
||||||
|
orderBy: orderBy,
|
||||||
|
page: perPage,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
enqueueSnackbar('Data berhasil di Export', {
|
||||||
|
variant: 'success',
|
||||||
|
anchorOrigin: { horizontal: 'right', vertical: 'top' },
|
||||||
|
});
|
||||||
|
setIsLoading(false)
|
||||||
|
|
||||||
|
document.location.href = res.data.data.file_url;
|
||||||
|
})
|
||||||
|
.catch((err) =>
|
||||||
|
enqueueSnackbar('Data Gagal di Export', {
|
||||||
|
variant: 'error',
|
||||||
|
anchorOrigin: { horizontal: 'right', vertical: 'top' },
|
||||||
|
})
|
||||||
|
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function SearchInput(props: any) {
|
||||||
|
// SEARCH
|
||||||
|
const searchInput = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleSearchChange = (event: any) => {
|
||||||
|
const newSearchText = event.target.value ?? '';
|
||||||
|
setSearchText(newSearchText);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearchSubmit = (event: any) => {
|
||||||
|
event.preventDefault();
|
||||||
|
props.onSearch({ search: searchText }); // Trigger to Parent
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleGetData = (type :string) => {
|
||||||
|
axios.get(`claims/1/data-claim`)
|
||||||
|
.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();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Trigger First Search
|
||||||
|
// setSearchText(searchParams.get('search') ?? '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
||||||
|
<Stack direction={'row'} spacing={2} sx={{ mb: 2 }}>
|
||||||
|
<TextField
|
||||||
|
id="search-input"
|
||||||
|
ref={searchInput}
|
||||||
|
label="Search"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
onChange={handleSearchChange}
|
||||||
|
value={searchText}
|
||||||
|
placeholder='Search Code or Member ID...'
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<Download />}
|
||||||
|
onClick={() => handleGetData('DO')}
|
||||||
|
sx={{ p: 1.8 }}
|
||||||
|
>
|
||||||
|
Export
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ImportForm(props: any) {
|
||||||
|
// IMPORT
|
||||||
|
// Create Button Menu
|
||||||
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||||
|
<SearchInput onSearch={applyFilter} />
|
||||||
|
{/* <Button
|
||||||
|
variant="outlined"
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
sx={{ p: 1.8 }}
|
||||||
|
onClick={() => {
|
||||||
|
navigate('/claims/create');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Create
|
||||||
|
</Button> */}
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchInput = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
|
||||||
|
//handle search
|
||||||
|
const handleSearchChange = (event: any) => {
|
||||||
|
const newSearchText = event.target.value ?? '';
|
||||||
|
setSearchText(newSearchText);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearchSubmit = (event: any) => {
|
||||||
|
event.preventDefault();
|
||||||
|
loadDataTableData();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Trigger First Search
|
||||||
|
//setSearchText(searchText);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const item = [
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
value: '',
|
||||||
|
name: 'Semua',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// const handleClick = () => {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Dummy Default Data
|
||||||
|
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||||
|
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>(
|
||||||
|
LaravelPaginatedDataDefault
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const loadDataTableData = async (appliedFilter: any | null = null) => {
|
||||||
|
setDataTableLoading(true);
|
||||||
|
const year = startDate?.getFullYear();
|
||||||
|
const month = (startDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit
|
||||||
|
const day = startDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit
|
||||||
|
|
||||||
|
const formattedDate = year && month && day ? `${year}-${month}-${day}` : '';
|
||||||
|
|
||||||
|
const year1 = endDate?.getFullYear();
|
||||||
|
const month1 = (endDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit
|
||||||
|
const day1 = endDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit
|
||||||
|
|
||||||
|
const formattedDate1 = year1 && month1 && day1 ? `${year1}-${month1}-${day1}` : '';
|
||||||
|
|
||||||
|
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||||
|
const response = await axios.get('/claims-files-provider', {
|
||||||
|
params: {
|
||||||
|
search: searchText,
|
||||||
|
start_date: formattedDate ? formattedDate : null,
|
||||||
|
end_date:formattedDate1,
|
||||||
|
provider: dataProvider,
|
||||||
|
order: order,
|
||||||
|
orderBy: orderBy,
|
||||||
|
page: perPage,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setDataTableLoading(false);
|
||||||
|
|
||||||
|
setDataTableData(response.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getProvider = async () => {
|
||||||
|
const response = await axios.get('/claims/get-provider');
|
||||||
|
setProviders(response.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const applyFilter = async (searchFilter: { search: string }) => {
|
||||||
|
await loadDataTableData(searchFilter);
|
||||||
|
setSearchParams(searchFilter);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePageChange = (event: ChangeEvent, value: number): void => {
|
||||||
|
setPerPage(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const [openDialogSubmit, setOpenDialogSubmit] = useState(false);
|
||||||
|
const handleCloseDialogSubmit = () => {
|
||||||
|
setOpenDialogSubmit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toTitleCase(str: string | null) {
|
||||||
|
return str.replace(/\w\S*/g, function(txt) {
|
||||||
|
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const [approve, setApprove] = useState('');
|
||||||
|
|
||||||
|
const [reasonDecline, setReasonDecline] = useState('');
|
||||||
|
|
||||||
|
const handleReasonDeclineChange = (event) => {
|
||||||
|
setReasonDecline(event.target.value);
|
||||||
|
// Tambahkan logika yang diperlukan di sini
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmitData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post('download-zip', { selectedRows: selectedRows });
|
||||||
|
const fileUrl = response.data.file_url; // Perbaikan disini
|
||||||
|
enqueueSnackbar('Data berhasil di download', { variant: 'success' });
|
||||||
|
window.open(fileUrl, '_blank');
|
||||||
|
setOpenDialogSubmit(false);
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 5000); // Reload the page after 5 seconds
|
||||||
|
} catch (error) {
|
||||||
|
enqueueSnackbar('Data Gagal di download', { variant: 'error' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmitData1 = () => {
|
||||||
|
//approve or decline
|
||||||
|
if (!reasonDecline && approve == 'decline') {
|
||||||
|
enqueueSnackbar('Mohon isi alasan', { variant: 'warning' });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Promise.all(selectedRows.map(send_bulk))
|
||||||
|
.then(() => {
|
||||||
|
enqueueSnackbar('All requests processed successfully', { variant: 'success' });
|
||||||
|
setOpenDialogSubmit(false);
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 5000); // Reload the page after 5 seconds
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
enqueueSnackbar(error.response?.data?.message ?? 'Something went wrong!', { variant: 'error' });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function send_bulk(id) {
|
||||||
|
return axios.post(`claims/${id}/${approve}`, { reasonDecline: reasonDecline });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
|
const createMenu = Boolean(anchorEl);
|
||||||
|
const importClaimManagement = useRef<HTMLInputElement>(null);
|
||||||
|
const [currentImportFileName, setCurrentImportFileName] = useState(null);
|
||||||
|
const [importLoading, setImportLoading] = useState(false);
|
||||||
|
const [importResult, setImportResult] = useState(null);
|
||||||
|
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
};
|
||||||
|
const handleClose = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
};
|
||||||
|
const handleImportButton = () => {
|
||||||
|
if (importClaimManagement?.current) {
|
||||||
|
handleClose();
|
||||||
|
importClaimManagement.current ? importClaimManagement.current.click() : console.log('No File selected');
|
||||||
|
} else {
|
||||||
|
alert('No file selected');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleCancelImportButton = () => {
|
||||||
|
if(importClaimManagement.current)
|
||||||
|
{
|
||||||
|
importClaimManagement.current.value = '';
|
||||||
|
importClaimManagement.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(importClaimManagement.current && importClaimManagement.current.files)
|
||||||
|
{
|
||||||
|
if (importClaimManagement.current?.files.length) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', importClaimManagement.current?.files[0]);
|
||||||
|
setImportLoading(true);
|
||||||
|
axios
|
||||||
|
.post('claims/import', formData)
|
||||||
|
.then((response) => {
|
||||||
|
handleCancelImportButton();
|
||||||
|
loadDataTableData();
|
||||||
|
setImportResult(response.data);
|
||||||
|
setImportLoading(false);
|
||||||
|
enqueueSnackbar('Success Import Claim Managemenet', { variant: 'success' });
|
||||||
|
})
|
||||||
|
.catch((response) => {
|
||||||
|
enqueueSnackbar(
|
||||||
|
'Looks like something went wrong. Please check your data and try again. ' +
|
||||||
|
response.message,
|
||||||
|
{ variant: 'error' }
|
||||||
|
);
|
||||||
|
setImportLoading(false);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
enqueueSnackbar('No File Selected', { variant: 'warning' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleGetTemplate = () => {
|
||||||
|
axios.get('claims/download-template').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 handleExportReportFiled = async () => {
|
||||||
|
|
||||||
|
await axios
|
||||||
|
.post('claims/exportFiled', { params: importResult?.data.result_rows })
|
||||||
|
.then((res) => {
|
||||||
|
enqueueSnackbar('Data berhasil di Export', {
|
||||||
|
variant: 'success',
|
||||||
|
anchorOrigin: { horizontal: 'right', vertical: 'top' },
|
||||||
|
});
|
||||||
|
setIsLoading(false)
|
||||||
|
|
||||||
|
document.location.href = res.data.data.file_url;
|
||||||
|
})
|
||||||
|
.catch((err) =>
|
||||||
|
enqueueSnackbar('Data Gagal di Export', {
|
||||||
|
variant: 'error',
|
||||||
|
anchorOrigin: { horizontal: 'right', vertical: 'top' },
|
||||||
|
})
|
||||||
|
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// loadDataTableData();
|
||||||
|
// getProvider();
|
||||||
|
// }, []);
|
||||||
|
|
||||||
|
const headStyle = {
|
||||||
|
fontWeight: 'bold',
|
||||||
|
};
|
||||||
|
const headCells = [
|
||||||
|
{
|
||||||
|
id: 'created_at',
|
||||||
|
align: 'left',
|
||||||
|
label: 'Date Submission',
|
||||||
|
isSort: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'code',
|
||||||
|
align: 'left',
|
||||||
|
label: 'Code',
|
||||||
|
isSort: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'name',
|
||||||
|
align: 'left',
|
||||||
|
label: 'Name',
|
||||||
|
isSort: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'provider',
|
||||||
|
align: 'left',
|
||||||
|
label: 'Provider',
|
||||||
|
isSort: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'files',
|
||||||
|
align: 'left',
|
||||||
|
label: 'Nama File',
|
||||||
|
isSort: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const orders = {
|
||||||
|
order: order,
|
||||||
|
setOrder: setOrder,
|
||||||
|
orderBy: orderBy,
|
||||||
|
setOrderBy: setOrderBy,
|
||||||
|
};
|
||||||
|
const createSortHandler = (property: string) => (event: React.MouseEvent<unknown>) => {
|
||||||
|
handleRequestSort(event, property);
|
||||||
|
};
|
||||||
|
const handleRequestSort = async (event: React.MouseEvent<unknown>, property: string) => {
|
||||||
|
const isAsc = orders?.orderBy === property && orders?.order === 'asc';
|
||||||
|
|
||||||
|
orders?.setOrder(isAsc ? 'desc' : 'asc');
|
||||||
|
orders?.setOrderBy(property);
|
||||||
|
};
|
||||||
|
// Called on every row to map the data to the columns
|
||||||
|
function createData(data: Claims): Claims {
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
/* ------------------ TABLE ROW ------------------ */
|
||||||
|
}
|
||||||
|
function Row(props: { row: ReturnType<typeof createData>, isSelected: boolean, onSelect: (id: string) => void }) {
|
||||||
|
const { row, isSelected, onSelect } = props;
|
||||||
|
// Memperbaiki destrukturisasi props
|
||||||
|
|
||||||
|
const handleRowCheckboxChange = () => {
|
||||||
|
onSelect(row.id); // Panggil fungsi onSelect dari komponen induk dengan id baris saat checkbox di baris diklik
|
||||||
|
};
|
||||||
|
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
|
|
||||||
|
const test = 1000;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||||
|
{/* <TableCell>
|
||||||
|
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||||
|
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||||
|
</IconButton>
|
||||||
|
</TableCell> */}
|
||||||
|
<TableCell align="left">
|
||||||
|
<Checkbox checked={isSelected} onChange={handleRowCheckboxChange} />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="left">{row?.created_at ? fDateTime(row?.created_at) : ''}</TableCell>
|
||||||
|
<TableCell align="left">{row?.code}</TableCell>
|
||||||
|
{/* <TableCell align="left">{row.code}</TableCell> */}
|
||||||
|
<TableCell align="left">{row?.name}</TableCell>
|
||||||
|
<TableCell align="left">{row?.provider}</TableCell>
|
||||||
|
<TableCell align='left'>
|
||||||
|
<a
|
||||||
|
href={row.path}
|
||||||
|
style={{ cursor: 'pointer', textDecoration: 'none', color: '#19BBBB' }}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<Typography variant="body2" gutterBottom>{row.files ? row.files : '-'}</Typography>
|
||||||
|
</a>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
{/* COLLAPSIBLE ROW */}
|
||||||
|
<TableRow>
|
||||||
|
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
|
||||||
|
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||||
|
{/* <Box sx={{ borderBottom: 1 }}>
|
||||||
|
<Typography variant="body2" gutterBottom component="div">
|
||||||
|
Description : {row.description}
|
||||||
|
</Typography>
|
||||||
|
</Box> */}
|
||||||
|
</Collapse>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
/* ------------------ END TABLE ROW ------------------ */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function TableContent() {
|
||||||
|
return (
|
||||||
|
<Table aria-label="collapsible table">
|
||||||
|
{/* ------------------ TABLE HEADER ------------------ */}
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
{selectedRows.length > 0 ? (
|
||||||
|
<>
|
||||||
|
<TableCell style={{ backgroundColor: '#D1F1F1' }} align="left" colSpan={2}>
|
||||||
|
<Stack direction="row">
|
||||||
|
<Checkbox checked={selectAll} onChange={handleSelectAll} />
|
||||||
|
{selectedRows.length > 0 ? selectedRows.length : '0'} <Typography variant='subtitle2'>Selected</Typography>
|
||||||
|
</Stack>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={{ backgroundColor: '#D1F1F1' }} align="left" colSpan={6}>
|
||||||
|
|
||||||
|
</TableCell>
|
||||||
|
{/* <TableCell style={{ backgroundColor: '#D1F1F1' }} align="right" colSpan={2}>
|
||||||
|
<Button variant="text" color="error" startIcon={<CancelIcon />} onClick={() => {setOpenDialogSubmit(true);
|
||||||
|
setApprove('decline');}}>
|
||||||
|
<Typography variant='subtitle2'>Decline</Typography>
|
||||||
|
</Button>
|
||||||
|
</TableCell> */}
|
||||||
|
<TableCell style={{ backgroundColor: '#D1F1F1' }} align="left" colSpan={4}>
|
||||||
|
<Button variant="text" color="primary" startIcon={<CheckCircleIcon />} onClick={() => {setOpenDialogSubmit(true);
|
||||||
|
setApprove('approve');}}>
|
||||||
|
<Typography variant='subtitle2'>Download</Typography>
|
||||||
|
</Button>
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<TableCell style={headStyle} align="left">
|
||||||
|
<Checkbox checked={selectAll} onChange={handleSelectAll} />
|
||||||
|
</TableCell>
|
||||||
|
{headCells &&
|
||||||
|
headCells.map((headCell, index) => (
|
||||||
|
<TableCell
|
||||||
|
key={index}
|
||||||
|
sortDirection={orders?.orderBy === headCell.id ? orders.order : false}
|
||||||
|
// @ts-ignore
|
||||||
|
align={headCell.align}
|
||||||
|
sx={{ padding: 2 }}
|
||||||
|
width={headCell.width ? headCell.width : 'auto'}
|
||||||
|
>
|
||||||
|
{headCell.isSort ? (
|
||||||
|
<TableSortLabel
|
||||||
|
active={orders?.orderBy === headCell.id}
|
||||||
|
direction={orders?.orderBy === headCell.id ? orders.order : 'asc'}
|
||||||
|
onClick={createSortHandler(headCell.id)}
|
||||||
|
>
|
||||||
|
{headCell.label}
|
||||||
|
{orders?.orderBy === headCell.id ? (
|
||||||
|
<Box component="span" sx={visuallyHidden}>
|
||||||
|
{orders.order === 'desc' ? 'sorted descending' : 'sorted ascending'}
|
||||||
|
</Box>
|
||||||
|
) : null}
|
||||||
|
</TableSortLabel>
|
||||||
|
) : (
|
||||||
|
headCell.label
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
{/* ------------------ END TABLE HEADER ------------------ */}
|
||||||
|
|
||||||
|
{/* ------------------ TABLE ROW ------------------ */}
|
||||||
|
{dataTableIsLoading ? (
|
||||||
|
<TableBody>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={11} align="center">
|
||||||
|
Loading
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
) : dataTableData.data.length === 0 ? (
|
||||||
|
<TableBody>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={11} align="center">
|
||||||
|
No Data
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
) : (
|
||||||
|
<TableBody>
|
||||||
|
{dataTableData.data.map((row) => (
|
||||||
|
<Row key={row.id} row={row} isSelected={selectedRows.includes(row.id)} onSelect={handleRowSelect} />
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
)}
|
||||||
|
{/* ------------------ END TABLE ROW ------------------ */}
|
||||||
|
</Table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={2}
|
||||||
|
sx={{ p: 2, justifyContent: 'space-between', alignItems: 'center' }}
|
||||||
|
>
|
||||||
|
<Grid item xs={12} md={12} lg={12}>
|
||||||
|
<form style={{ width: '100%' }}>
|
||||||
|
<Grid container spacing={1} sx={{ justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
id="file"
|
||||||
|
ref={importClaimManagement}
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
onChange={handleImportChange}
|
||||||
|
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain"
|
||||||
|
/>
|
||||||
|
{!currentImportFileName && (
|
||||||
|
<>
|
||||||
|
<Grid item xs={12} md={4}>
|
||||||
|
<TextField
|
||||||
|
id="search-input"
|
||||||
|
ref={searchInput}
|
||||||
|
variant="outlined"
|
||||||
|
value={searchText}
|
||||||
|
fullWidth
|
||||||
|
onChange={handleSearchChange}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
handleSearchSubmit(event);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<Search />
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
placeholder: 'Search Code or Name',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={5} display="flex" sx={{ gap: '16px' }}>
|
||||||
|
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||||
|
<DesktopDatePicker
|
||||||
|
value={startDate}
|
||||||
|
inputFormat="dd/MM/yyyy"
|
||||||
|
onChange={(value) => {
|
||||||
|
|
||||||
|
// loadDataTableData();
|
||||||
|
setStartDate(value);
|
||||||
|
}}
|
||||||
|
renderInput={(params) => <TextField {...params} fullWidth label="Start" />}
|
||||||
|
/>
|
||||||
|
</LocalizationProvider>
|
||||||
|
|
||||||
|
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||||
|
<DesktopDatePicker
|
||||||
|
value={endDate}
|
||||||
|
inputFormat="dd/MM/yyyy"
|
||||||
|
onChange={(value) => {
|
||||||
|
setEndDate(value);
|
||||||
|
}}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
fullWidth
|
||||||
|
label="End"
|
||||||
|
// error={!!error}
|
||||||
|
// helperText={error?.message}
|
||||||
|
// {...other}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</LocalizationProvider>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={3}>
|
||||||
|
{
|
||||||
|
providers ? (
|
||||||
|
<Autocomplete
|
||||||
|
id="provider"
|
||||||
|
options={providers}
|
||||||
|
getOptionLabel={(option) => option.name || ''}
|
||||||
|
value={providers.find((item) => item.id === dataProvider) || null}
|
||||||
|
onChange={(event, value) => {
|
||||||
|
if (value) {
|
||||||
|
setDataProvider(value.id);
|
||||||
|
} else {
|
||||||
|
setDataProvider(null);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
label="Provider"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
):(
|
||||||
|
<>
|
||||||
|
<Typography variant='body2' align='center'>Loading...</Typography>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Grid>
|
||||||
|
{/* <Grid item xs={12} md={3} display="flex" sx={{ gap: '16px' }}>
|
||||||
|
<FormControl >
|
||||||
|
<LoadingButton
|
||||||
|
id="upload-button"
|
||||||
|
variant="outlined"
|
||||||
|
startIcon={<UploadIcon />}
|
||||||
|
sx={{ p: 1.8 }}
|
||||||
|
loading={isLoadingImport}
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
<Typography variant="inherit" sx={{ marginLeft: 1 }}>
|
||||||
|
Import
|
||||||
|
</Typography>
|
||||||
|
</LoadingButton>
|
||||||
|
<Menu
|
||||||
|
id="import-button"
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={createMenu}
|
||||||
|
onClose={handleClose}
|
||||||
|
MenuListProps={{
|
||||||
|
'aria-labelledby': 'basic-button',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem onClick={handleImportButton}>
|
||||||
|
<Typography variant='body2'>Import</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
handleGetTemplate();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant='body2'> Download Template</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</FormControl>
|
||||||
|
<FormControl >
|
||||||
|
<LoadingButton
|
||||||
|
id="upload-button"
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<Download />}
|
||||||
|
sx={{ p: 1.8 }}
|
||||||
|
onClick={handleExportReport}
|
||||||
|
loading={isLoading}
|
||||||
|
>
|
||||||
|
<Typography variant="inherit" sx={{ marginLeft: 1 }}>
|
||||||
|
Export
|
||||||
|
</Typography>
|
||||||
|
</LoadingButton>
|
||||||
|
</FormControl>
|
||||||
|
</Grid> */}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{currentImportFileName && (
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
|
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||||
|
<ButtonGroup variant="outlined" aria-label="outlined button group" fullWidth>
|
||||||
|
<Button onClick={handleImportButton} fullWidth>
|
||||||
|
{currentImportFileName ?? 'No File Selected'}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleCancelImportButton}
|
||||||
|
size="small"
|
||||||
|
fullWidth={false}
|
||||||
|
sx={{ p: 1.8 }}
|
||||||
|
>
|
||||||
|
<CancelIcon color="error" />
|
||||||
|
</Button>
|
||||||
|
</ButtonGroup>
|
||||||
|
|
||||||
|
<LoadingButton
|
||||||
|
id="upload-button"
|
||||||
|
variant="outlined"
|
||||||
|
startIcon={<UploadIcon />}
|
||||||
|
sx={{ p: 1.8 }}
|
||||||
|
onClick={handleUpload}
|
||||||
|
loading={importLoading}
|
||||||
|
>
|
||||||
|
Upload
|
||||||
|
</LoadingButton>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
{importResult && (
|
||||||
|
<Stack direction={'row'} sx={{ px: 2, pb: 2 }}>
|
||||||
|
<Box sx={{ color: 'text.secondary' }}>
|
||||||
|
Last Import Result :{' '}
|
||||||
|
<Box sx={{ color: 'success.main', display: 'inline' }}>
|
||||||
|
{importResult.data.total_success_row ?? 0}
|
||||||
|
</Box>{' '}
|
||||||
|
Row Processed,{' '}
|
||||||
|
<Box sx={{ color: 'error.main', display: 'inline' }}>
|
||||||
|
{importResult.data.total_failed_row}
|
||||||
|
</Box>{' '}
|
||||||
|
Failed,
|
||||||
|
{/* {importResult.data.failed_rows.map((row, index) => (
|
||||||
|
<Typography variant='body' key={index} color="error"> [Code={row.code ? row.code : 'Required'}]</Typography>
|
||||||
|
))} */}
|
||||||
|
Report:
|
||||||
|
<u onClick={handleExportReportFiled} style={{cursor:'pointer'}}>Download Data Result Import</u>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
</form>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<DataTable
|
||||||
|
isLoading={dataTableIsLoading}
|
||||||
|
lastRequest={0}
|
||||||
|
data={dataTableData}
|
||||||
|
handlePageChange={handlePageChange}
|
||||||
|
TableContent={<TableContent />}
|
||||||
|
/>
|
||||||
|
<Dialog open={openDialogSubmit} onClose={handleCloseDialogSubmit} fullWidth={true}>
|
||||||
|
<DialogTitle sx={{ backgroundColor: '#19BBBB', color: '#FFF', padding: 2 }}>
|
||||||
|
<Stack direction="row" alignItems="center" justifyContent="space-between">
|
||||||
|
<Stack direction="row" alignItems='center' spacing={1}>
|
||||||
|
<Typography variant="h6">Confirmation</Typography>
|
||||||
|
</Stack>
|
||||||
|
<IconButton sx={{ color: '#FFF' }} onClick={handleCloseDialogSubmit}>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Stack>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
|
||||||
|
<Stack spacing={2} padding={2}>
|
||||||
|
<Typography variant='body1'>Are you sure to Download this files selected ?</Typography>
|
||||||
|
{approve == "decline" ? (
|
||||||
|
<Stack direction='row' spacing={2} marginTop={2}>
|
||||||
|
<TextField
|
||||||
|
id="outlined-multiline-static"
|
||||||
|
label="Reason decline"
|
||||||
|
multiline
|
||||||
|
rows={4} // Tentukan jumlah baris yang diinginkan
|
||||||
|
defaultValue=""
|
||||||
|
onChange={handleReasonDeclineChange}
|
||||||
|
variant="outlined"
|
||||||
|
sx={{width:'100%'}}
|
||||||
|
// fullWidth // Gunakan ini jika Anda ingin input memenuhi lebar Stack
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
): ''}
|
||||||
|
</Stack>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialogSubmit}>Cancel</Button>
|
||||||
|
<Button sx={{backgroundColor: (approve === 'decline' ? '' : '#19BBBB'), color: (approve === 'decline' ? '#FF4842' : ''), borderColor: '#FF4842'}} onClick={handleSubmitData} variant={(approve === 'decline' ? 'outlined' : 'contained')}>{(approve === "decline" ? 'Decline' : 'Download')}</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -418,6 +418,10 @@ export default function Router() {
|
|||||||
path: 'report/appointments/:id/edit',
|
path: 'report/appointments/:id/edit',
|
||||||
element: <AppointmentCreate />,
|
element: <AppointmentCreate />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'report/files-provider',
|
||||||
|
element: <FilesProvider />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'report/live-chat',
|
path: 'report/live-chat',
|
||||||
element: <Livechat />,
|
element: <Livechat />,
|
||||||
@@ -507,6 +511,18 @@ export default function Router() {
|
|||||||
path: 'custormer-service/final-log/detail/:id',
|
path: 'custormer-service/final-log/detail/:id',
|
||||||
element: <FinalLogDetail />,
|
element: <FinalLogDetail />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'e-prescription/live-chat',
|
||||||
|
element: <EPrescription />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'e-prescription/live-chat/:id',
|
||||||
|
element: <EPrescriptionCreate />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'e-prescription/live-chat/:id/show',
|
||||||
|
element: <EPrescriptionShow />,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
@@ -662,10 +678,17 @@ const Appointment = Loadable(lazy(() => import('../pages/Report/Appointments/Ind
|
|||||||
const AppointmentCreate = Loadable(lazy(() => import('../pages/Report/Appointments/Create')));
|
const AppointmentCreate = Loadable(lazy(() => import('../pages/Report/Appointments/Create')));
|
||||||
const AppointmentShow = Loadable(lazy(() => import('../pages/Report/Appointments/Show')));
|
const AppointmentShow = Loadable(lazy(() => import('../pages/Report/Appointments/Show')));
|
||||||
|
|
||||||
|
const FilesProvider = Loadable(lazy(() => import('../pages/Report/FilesProvider/Index')));
|
||||||
|
|
||||||
const Livechat = Loadable(lazy(() => import('../pages/Report/Livechat/Index')));
|
const Livechat = Loadable(lazy(() => import('../pages/Report/Livechat/Index')));
|
||||||
const LivechatCreate = Loadable(lazy(() => import('../pages/Report/Livechat/Create')));
|
const LivechatCreate = Loadable(lazy(() => import('../pages/Report/Livechat/Create')));
|
||||||
const LivechatShow = Loadable(lazy(() => import('../pages/Report/Livechat/Show')));
|
const LivechatShow = Loadable(lazy(() => import('../pages/Report/Livechat/Show')));
|
||||||
|
|
||||||
|
|
||||||
|
const EPrescription = Loadable(lazy(() => import('../pages/EPrescription/Livechat/Index')));
|
||||||
|
const EPrescriptionCreate = Loadable(lazy(() => import('../pages/EPrescription/Livechat/Create')));
|
||||||
|
const EPrescriptionShow = Loadable(lazy(() => import('../pages/EPrescription/Livechat/Show')));
|
||||||
|
|
||||||
const LinksehatPayment = Loadable(lazy(() => import('../pages/Report/LinksehatPayments/Index')));
|
const LinksehatPayment = Loadable(lazy(() => import('../pages/Report/LinksehatPayments/Index')));
|
||||||
|
|
||||||
const MasterDrug = Loadable(lazy(() => import('../pages/Master/Drug/Index')));
|
const MasterDrug = Loadable(lazy(() => import('../pages/Master/Drug/Index')));
|
||||||
|
|||||||
@@ -7,4 +7,6 @@ return [
|
|||||||
'password' => 'Password wrong. Please try again.',
|
'password' => 'Password wrong. Please try again.',
|
||||||
'read_notification' => 'Notification has been read.',
|
'read_notification' => 'Notification has been read.',
|
||||||
'already_exists' => 'Data already exists.',
|
'already_exists' => 'Data already exists.',
|
||||||
|
'logout' => 'User logged out successfully.',
|
||||||
|
'token_expired' => 'Token has expired. Please re-request the token.'
|
||||||
];
|
];
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user