Merge remote-tracking branch 'origin/staging' into origin/production

This commit is contained in:
Server D3 Linksehat
2024-10-14 11:31:59 +07:00
91 changed files with 2823 additions and 12555 deletions

0
.editorconfig Normal file → Executable file
View File

2
.gitignore vendored
View File

@@ -23,4 +23,4 @@ yarn-error.log
/public/hospital-portal
/public/hospital-portal-staging
/public/files
/public/files

0
.styleci.yml Normal file → Executable file
View File

View File

@@ -34,24 +34,51 @@ class AuthController extends Controller
return Helper::responseJson(statusCode: Response::HTTP_NOT_FOUND, message: $message);
}
// $token = rand(1000, 9999); // Menghasilkan angka acak antara 100000 dan 999999
$token = 4444; // Menghasilkan angka acak antara 100000 dan 999999
if($request->phoneOrEmail == 'manager+one@gmail.com' || $request->phoneOrEmail == 'manager+two@gmail.com')
{
$token = 4444;
}
if (filter_var($request->phoneOrEmail, FILTER_VALIDATE_EMAIL)) {
User::query()->find($user->id)->update([
'email' => $request->phoneOrEmail,
'otp' => $token,
'otp_created_at' => now()
]);
} else {
User::query()->find($user->id)->update([
'phone' => $request->phoneOrEmail,
'otp' => $token,
'otp_created_at' => now()
]);
// if($request->phoneOrEmail == 'manager+one@gmail.com' || $request->phoneOrEmail == 'manager+two@gmail.com')
// {
// $token = 4444;
// }
// if (filter_var($request->phoneOrEmail, FILTER_VALIDATE_EMAIL)) {
// User::query()->find($user->id)->update([
// 'email' => $request->phoneOrEmail,
// 'otp' => $token,
// 'otp_created_at' => now()
// ]);
// } else {
// User::query()->find($user->id)->update([
// 'phone' => $request->phoneOrEmail,
// 'otp' => $token,
// 'otp_created_at' => now()
// ]);
// }
// // TODO Send the OTP
// if (filter_var($request->phoneOrEmail, FILTER_VALIDATE_EMAIL)) {
// // Send Email
// //send to alarm
// if($request->phoneOrEmail != 'manager+one@gmail.com' && $request->phoneOrEmail != 'manager+two@gmail.com')
// {
// $nameTo = 'User';
// $dataEmail = [
// 'email' => $request->phoneOrEmail,
// 'name' => $nameTo,
// 'subject' => 'OTP Login Client Portal Tanggal '. date('Y-m-d H:i:s'),
// 'body' => View::make('email/forgot_password', ['token' => $token])->render(),
// ];
// Helper::sendEmail($dataEmail);
// }
// } else {
// // Send Whatsapp
// }
// return Helper::responseJson(message: 'OTP Terkirim');
if (!Hash::check($request->password, $user->password)) {
return response(['message' => 'Password Salah'], 403);
}
return Helper::responseJson(

View File

@@ -0,0 +1,93 @@
<?php
namespace Modules\HospitalPortal\Helpers;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use DateTime;
use DateTimeZone;
class GrabHelper
{
protected $client;
public function __construct()
{
$this->client = new Client();
}
public function getToken()
{
$url = env('TOKEN_URL_GRAB');
$headers = [
'Content-Type' => 'application/json',
];
$body = json_encode([
'client_id' => env('CLIENT_ID_GRAB'),
'client_secret' => env('CLIENT_SECRET_GRAB'),
'grant_type' => 'client_credentials',
'scope' => 'grab_express.partner_deliveries',
]);
$request = new Request('POST', $url, $headers, $body);
$response = $this->client->send($request);
$data = json_decode($response->getBody()->getContents(), true);
return $data['access_token'] ?? null;
}
public function createDelivery($token,$body)
{
$url = env('BASE_URL_GRAB').'/v1/deliveries';
$headers = [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $token,
];
$request = new Request('POST', $url, $headers, $body);
$response = $this->client->send($request);
return $response->getBody()->getContents();
}
public function normalizePhoneNumber($phoneNumber) {
// Remove any non-digit characters (e.g., '+', '-', spaces)
$phoneNumber = preg_replace('/\D/', '', $phoneNumber);
// Check if the cleaned phone number is numeric
if (!is_numeric($phoneNumber)) {
return null; // Return false or handle the error as needed
}
// Handle phone numbers starting with '62' or '+62'
if (substr($phoneNumber, 0, 2) === '62') {
$phoneNumber = '0' . substr($phoneNumber, 2);
}
// Handle phone numbers that already start with '8'
if (substr($phoneNumber, 0, 1) === '8') {
$phoneNumber = '0' . $phoneNumber;
}
return $phoneNumber;
}
public function getScheduleTimes()
{
// Create a DateTime object for the current time in Jakarta timezone
$pickupTimeFrom = new DateTime('now', new DateTimeZone('Asia/Jakarta'));
// Add 30 minutes to the current time for pickupTimeFrom
$pickupTimeFrom->modify('+30 minutes');
// Clone the pickupTimeFrom to calculate pickupTimeTo
$pickupTimeTo = clone $pickupTimeFrom;
// Add 1 hour to pickupTimeFrom for pickupTimeTo
$pickupTimeTo->modify('+1 hour');
// Format the times to ISO 8601 format (e.g., 2024-10-02T12:37:28+07:00)
return [
"pickupTimeFrom" => $pickupTimeFrom->format(DateTime::ATOM),
"pickupTimeTo" => $pickupTimeTo->format(DateTime::ATOM),
];
}
}

View File

@@ -0,0 +1,695 @@
<?php
namespace Modules\HospitalPortal\Http\Controllers;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use App\Helpers\Helper;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Modules\HospitalPortal\Helpers\ApiResponse;
use Modules\HospitalPortal\Helpers\GrabHelper;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
class ApotekController extends Controller
{
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index(Request $request)
{
$limit = $request->has('per_page') ? $request->input('per_page') : 10;
$results = DB::connection('oldlms')->table('tx_prescriptions')
->join('tx_prescription_orders', 'tx_prescription_orders.nIDPrescription', '=', 'tx_prescriptions.nID')
->join('tm_users', 'tm_users.nID', '=', 'tx_prescriptions.nIDUser')
->when(auth()->user()->organization_id, function ($query, $organizationId) {
$query->where('tx_prescription_orders.nIDApotek', '=', $organizationId);
})
->when($request->input('search'), function ($query, $search) {
$query->where(function ($query) use ($search) {
$query->orWhere('tx_prescriptions.sKodeResep', 'like', "%" . $search . "%")
->orWhere('tm_users.sFirstName', 'like', "%" . $search . "%");
});
})
->when($request->has('orderBy'), function ($query) use ($request) {
$orderBy = $request->orderBy;
$direction = $request->order ?? 'asc';
if($orderBy == 'apotek')
{
$orderBy = 'nIDApotek';
}
$query->orderBy($orderBy, $direction);
})
->when($request->input('start_date') && !$request->input('end_date'), function ($query, $start_date) {
$query->where(function ($query) use ($start_date) {
$query->where('tx_prescriptions.dTanggalresep', '<', $start_date);
});
})
->when($request->input('status'), function ($query, $status) {
$query->where(function ($query) use ($status) {
$query->where('tx_prescription_orders.sStatus', '=', $status);
});
})
->select(
'tx_prescriptions.nID as id',
'tx_prescription_orders.nID as nID_orders',
'tx_prescriptions.nIDUser',
'tx_prescriptions.sKodeResep as no_resep',
'tx_prescriptions.dTanggalResep as tanggal',
'tx_prescription_orders.nIDApotek',
'tx_prescription_orders.sStatus as status',
'tx_prescription_orders.sStatus',
DB::raw('
CASE
WHEN tx_prescription_orders.sStatus = "waiting_pharmacy" THEN "Diterima"
WHEN tx_prescription_orders.sStatus = "order_prepared" THEN "Siap Diambil"
WHEN tx_prescription_orders.sStatus = "ready" THEN "Cari Kurir"
WHEN tx_prescription_orders.sStatus = "failed" THEN "Cari Kurir"
WHEN tx_prescription_orders.sStatus = "waiting_for_courir" THEN "Kurir Sudah Ambil Pesanan"
WHEN tx_prescription_orders.sStatus = "package_picked_up" THEN "Sedang diantar ke Alamat Tujuan"
WHEN tx_prescription_orders.sStatus = "package_on_delivery" THEN "Selesai"
ELSE ""
END AS button_accept'),
DB::raw('CONCAT(
COALESCE(tm_users.sFirstName, ""),
" ",
COALESCE(tm_users.sMiddleName, ""),
" ",
COALESCE(tm_users.sLastName, "")
) as pasien'),
DB::raw('
(SELECT CONCAT(
COALESCE(u.sFirstName, ""),
" ",
COALESCE(u.sMiddleName, ""),
" ",
COALESCE(u.sLastName, "")
)
FROM tm_dokter d
LEFT JOIN tm_users u ON u.nID = d.nIDUser
WHERE d.nID = tx_prescriptions.nIDDokter LIMIT 1) AS nama_dokter
'),
DB::raw('
(SELECT s.sSpesialis
FROM tm_dokter d
LEFT JOIN tm_spesialis s ON s.nID = d.nIDSpesialis
WHERE d.nID = tx_prescriptions.nIDDokter LIMIT 1) AS spesialis
'),
DB::raw('
(SELECT t.sSIP
FROM tm_dokter d
LEFT JOIN tx_jadwal_dokter t ON t.nIDDokter = d.nID
WHERE d.nID = tx_prescriptions.nIDDokter LIMIT 1) AS sip
'),
DB::raw('
(SELECT u.sPhone
FROM tm_dokter d
LEFT JOIN tm_users u ON u.nID = d.nIDUser
WHERE d.nID = tx_prescriptions.nIDDokter LIMIT 1) AS no_ponsel_dokter
'),
DB::raw('
(SELECT tm_users_detail.dTanggalLahir
FROM tm_users_detail
WHERE tm_users_detail.nIDUser = tm_users.nID LIMIT 1) AS tgl_lahir_pasien
'),
DB::raw('
(SELECT CASE
WHEN tm_users_detail.nIDJenisKelamin = 1 THEN "Male"
ELSE "Female"
END
FROM tm_users_detail
WHERE tm_users_detail.nIDUser = tm_users.nID LIMIT 1) AS jenis_kelamin_pasien
'),
DB::raw('
(SELECT CONCAT(tm_users_detail.sHeight, "/", tm_users_detail.sWeight)
FROM tm_users_detail
WHERE tm_users_detail.nIDUser = tm_users.nID LIMIT 1) AS tinggi_berat
'),
DB::raw('
(SELECT tm_users_insurance.sNoPolis
FROM tm_users_insurance
LEFT JOIN tm_insurance ON tm_users_insurance.nIDInsurance = tm_insurance.nID
WHERE tm_users_insurance.nIDUser = tx_prescriptions.nIDUser LIMIT 1) AS no_polis
'),
DB::raw('
(SELECT tm_insurance.sInsurance
FROM tm_users_insurance
LEFT JOIN tm_insurance ON tm_users_insurance.nIDInsurance = tm_insurance.nID
WHERE tm_users_insurance.nIDUser = tx_prescriptions.nIDUser LIMIT 1) AS perusahaan_asuransi
'),
DB::raw('
(SELECT tm_users_insurance.sCorporateName
FROM tm_users_insurance
LEFT JOIN tm_insurance ON tm_users_insurance.nIDInsurance = tm_insurance.nID
WHERE tm_users_insurance.nIDUser = tx_prescriptions.nIDUser LIMIT 1) AS nama_perusahaan
'),
DB::raw('
(SELECT tm_users_insurance.sProductCode
FROM tm_users_insurance
LEFT JOIN tm_insurance ON tm_users_insurance.nIDInsurance = tm_insurance.nID
WHERE tm_users_insurance.nIDUser = tx_prescriptions.nIDUser LIMIT 1) AS kode_produk
'),
DB::raw('
(
SELECT
CASE
WHEN tm_users_insurance.sPlanCode = "A" THEN "Alba"
WHEN tm_users_insurance.sPlanCode = "B" THEN "Blue"
WHEN tm_users_insurance.sPlanCode = "S" THEN "Silver"
WHEN tm_users_insurance.sPlanCode = "G" THEN "Gold"
WHEN tm_users_insurance.sPlanCode = "P" THEN "Platinum"
WHEN tm_users_insurance.sPlanCode = "D" THEN "Diamond"
ELSE ""
END AS kelas_asuransi
FROM tm_users_insurance
LEFT JOIN tm_insurance ON tm_users_insurance.nIDInsurance = tm_insurance.nID
WHERE tm_users_insurance.nIDUser = tx_prescriptions.nIDUser
LIMIT 1
) AS kelas_asuransi
'),
DB::raw('
(
SELECT
CASE
WHEN tm_hubungan_keluarga.sHubunganKeluarga = "Husband" THEN "S"
WHEN tm_hubungan_keluarga.sHubunganKeluarga = "Wife" THEN "I"
WHEN tm_hubungan_keluarga.sHubunganKeluarga = "Child" THEN "A"
ELSE "P"
END AS tipe_member
FROM tm_hubungan_keluarga
WHERE tm_hubungan_keluarga.nID = tm_users.nIDHubunganKeluarga
LIMIT 1
) AS tipe_member
'),
'tx_prescription_orders.sAddress AS alamat_penerima',
'tx_prescription_orders.sDeliveryMethod AS pengiriman',
'tx_prescription_orders.sDeliveryPrice AS total_kirim',
'tx_prescriptions.sNoRefProvider AS noref_dokter',
DB::raw('DATE_ADD(tx_prescriptions.dTanggalResep, INTERVAL 1 DAY) as valid_tanggal'),
'tx_prescriptions.sNomorPenjamin AS nomor_penjamin',
DB::raw('
(SELECT tx_livechat.dCreateOn
FROM tx_livechat
WHERE tx_livechat.nID = tx_prescriptions.nIDLivechat LIMIT 1) AS tgl_livechat
'),
'tx_prescriptions.sDiagnose as diagnosa',
'tx_prescription_orders.nDeliveryID',
'tx_prescription_orders.sDeliveryStatus'
)
->paginate($limit);
// Secret key for generating the token
$secret_key = env('SECRET_KEY_LMS');
// Transform the results to include the download link
$results->getCollection()->transform(function ($item) use ($secret_key) {
// Generate the token with the timestamp
$expiry_time = time() + 86400; // Token expiry time (1 day)
$token = hash_hmac('sha256', $item->id . $expiry_time, $secret_key);
// Construct the download link
$path = 'prescription/barcode-print-pdf/' . $item->id . '?token=' . urlencode($token) . '&expiry=' . $expiry_time;
$host = $_SERVER['HTTP_HOST']; // This will give you the host like 'linksehat.dev' or 'linksehat.com'
$base_url = "https://m.linksehat.dev/";
// Check if the host contains '.dev'
if (strpos($host, '.com') !== false) {
$base_url = "https://m.linksehat.com/";
}
$item->link_download = $base_url.$path;
return $item;
});
$apotekIds = $results->pluck(value: 'nIDApotek')->unique()->filter();
$organizations = DB::connection('mysql')->table('organizations')
->whereIn('id', $apotekIds)
->pluck('name', 'id');
$results->getCollection()->transform(function ($item) use ($organizations) {
$item->apotek = $organizations->get($item->nIDApotek, '-'); // Default to 'Unknown' if not found
return $item;
});
// Transform results to include allergies
$results->getCollection()->transform(function ($item) use ($organizations) {
// Get the allergies for each user
$allergies = $this->getAllergies($item->nIDUser);
// Concatenate the allergy description
$alergi_desc = '';
foreach ($allergies as $row) {
$alergi_desc .= $row->sAlergi . ' - ' . $row->sKeterangan . ', ';
}
// Set apotek and allergies data
$item->apotek = $organizations->get($item->nIDApotek, '-'); // Default to 'Unknown' if not found
$item->alergi_desc = rtrim($alergi_desc, ', '); // Remove the trailing comma
return $item;
});
// Extract unique Prescription IDs from the results
$prescriptionIDs = $results->pluck('id')->unique()->filter();
// Fetch prescription items based on Prescription IDs
$items = DB::connection('oldlms')->table('tx_prescription_items')
->whereIn('nIDPrescription', $prescriptionIDs)
->select('nIDPrescription', 'sItemName', 'sSigna', 'sTiming', 'sDuration', 'nQty', 'sNote')
->get()
->groupBy('nIDPrescription'); // Group items by their Prescription ID
// Final transformation: Attach prescription items to each prescription
$results->getCollection()->transform(function ($item) use ($items) {
$item->prescription_items = $items->get($item->id, collect())->map(function ($prescriptionItem) {
return [
'sItemName' => $prescriptionItem->sItemName,
'sSigna' => $prescriptionItem->sSigna,
'sTiming' => $prescriptionItem->sTiming,
'sDuration' => $prescriptionItem->sDuration,
'nQty' => $prescriptionItem->nQty,
'sNote' => $prescriptionItem->sNote,
];
});
return $item;
});
return response()->json(Helper::paginateResources($results));
}
public function getAllergies($nIDUser) {
return DB::connection('oldlms')
->table('tx_alergi_users as txa')
->join('tm_alergi as ta', 'ta.nID', '=', 'txa.nIDAlergi')
->select('ta.sAlergi', 'ta.sKeterangan')
->where('txa.nIDUser', $nIDUser)
->get();
}
/**
* Show the form for creating a new resource.
* @return Renderable
*/
public function create()
{
return view('hospitalportal::create');
}
/**
* Store a newly created resource in storage.
* @param Request $request
* @return Renderable
*/
public function store(Request $request)
{
//
}
/**
* Show the specified resource.
* @param int $id
* @return Renderable
*/
public function show($id)
{
return view('hospitalportal::show');
}
/**
* Show the form for editing the specified resource.
* @param int $id
* @return Renderable
*/
public function edit($id)
{
return view('hospitalportal::edit');
}
/**
* Update the specified resource in storage.
* @param Request $request
* @param int $id
* @return Renderable
*/
public function update(Request $request, $id)
{
$data = ['sStatus' => $request->sStatus];
$validator = Validator::make($request->all(), [
'sStatus' => 'required|string|max:255',
], [
'sStatus.required' => trans('Validation.required',['attribute' => 'Status']),
]);
if ($validator->fails())
{
return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
}
else
{
try {
// Define the valid transitions
$valid_transitions = [
'waiting_for_payment' => 'waiting_pharmacy',
'waiting_pharmacy' => 'order_prepared',
'order_prepared' => 'ready',
'ready' => 'waiting_for_courir',
'waiting_for_courir' => 'package_picked_up',
'package_picked_up' => 'package_on_delivery',
'package_on_delivery' => 'package_delivered'
];
// Get the current status from the request
$inputStatus = $request->sStatus;
// Check if the input status has a valid next status in the map
if (isset($valid_transitions[$inputStatus])) {
// Get the next status
$status = $valid_transitions[$inputStatus];
// Start the transaction
DB::connection('oldlms')->beginTransaction();
// Update the status in the database
DB::connection('oldlms')->table('tx_prescription_orders')
->where('tx_prescription_orders.nID', '=', $id)
->update([
'sStatus' => $status,
'sUpdateBy' => auth()->user()->id,
'dUpdateOn' => date('Y-m-d H:i:s'),
]);
// Insert the log
$prescriptionOrder = DB::connection('oldlms')
->table('tx_prescription_orders')
->where('tx_prescription_orders.nID', '=', $id)
->join('tx_delivery_orders', 'tx_delivery_orders.nIDPrescriptionOrder', '=', 'tx_prescription_orders.nID')
->select('tx_prescription_orders.*', 'tx_delivery_orders.*', 'tx_delivery_orders.nID as nIDDelivery') // Add specific columns you want to select
->first();
if ($prescriptionOrder) {
$createdBy = $prescriptionOrder->sCreateBy;
$nIDPrescription = $prescriptionOrder->nIDPrescription;
$nIDDeliveryOrder = $prescriptionOrder->nIDDelivery;
// Insert data into the tx_delivery_log table
DB::connection('oldlms')->table('tx_delivery_log')->insert([
'sStatus' => $prescriptionOrder->sDeliveryStatus,
'sStatusPrescription' => $status,
'nIDDeliveryOrder' => $nIDDeliveryOrder,
'nIDPrescription' => $nIDPrescription,
'dCreatedOn' => now(),
]);
}
// Commit the transaction
DB::connection('oldlms')->commit();
// Return success response
return ApiResponse::apiResponse("Success", $data, trans('Message.success'), 200);
} else {
// If the input status is not valid, return an error
return ApiResponse::apiResponse('Invalid Status', $data, 'The input status is not valid.', 400);
}
} catch (\Exception $e) {
// Rollback the transaction if an error occurs
DB::connection('oldlms')->rollBack();
// Handle error, could log or return as response
return ApiResponse::apiResponse('Server Error', $data, $e->getMessage(), 500);
}
}
}
public function getDriver(Request $request, $id)
{
$data = ['sStatus' => $request->sStatus];
// Validation
$validator = Validator::make($request->all(), [
'sStatus' => 'required|string|max:255',
], [
'sStatus.required' => trans('Validation.required', ['attribute' => 'Status']),
]);
if ($validator->fails()) {
return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
}
try {
// Fetch prescription data
$prescriptions = DB::connection('oldlms')->table('tx_prescription_orders')
->leftJoin('tx_prescriptions', 'tx_prescriptions.nID', '=', 'tx_prescription_orders.nIDPrescription')
->where('tx_prescription_orders.nID', '=', $id)
->select(
'tx_prescriptions.nIDUser',
'tx_prescriptions.nID as id_prescription',
'tx_prescriptions.sKodeResep as merchantOrderID',
'tx_prescription_orders.nIDApotek'
)
->first();
if (!$prescriptions) {
return ApiResponse::apiResponse('Not Found', [], 'Prescription not found', 404);
}
// Fetch prescription items (medicine data)
$items = DB::connection('oldlms')->table('tx_prescription_items')
->where('nIDPrescription', $prescriptions->id_prescription)
->select('nIDPrescription', 'sItemName', 'nQty', 'nHarga')
->get();
$packages = [];
foreach ($items as $item) {
$packages[] = [
'name' => $item->sItemName,
'description' => $item->sItemName,
'quantity' => (float)$item->nQty,
'price' => (float)$item->nHarga,
'dimensions' => [
'height' => 0,
'width' => 0,
'depth' => 0,
'weight' => 0,
]
];
}
// Fetch pharmacy (apotek) data
$apotek = DB::connection('mysql')->table('organizations')
->leftJoin('addresses', 'addresses.id', '=', 'organizations.main_address_id')
->where('organizations.id', '=', $prescriptions->nIDApotek)
->select('organizations.name as nama_apotek', 'addresses.text as alamat_apotek', 'addresses.lat', 'addresses.lng')
->first();
// Fetch patient (pasien) data
$pasien = DB::connection('oldlms')->table('tm_users')
->leftJoin('tm_users_detail', 'tm_users_detail.nIDuser', '=', 'tm_users.nID')
->where('tm_users.nID', '=', $prescriptions->nIDUser)
->select(
DB::raw('CONCAT(
COALESCE(tm_users.sFirstName, ""),
" ",
COALESCE(tm_users.sMiddleName, ""),
" ",
COALESCE(tm_users.sLastName, "")
) as nama_pasien'),
'tm_users.sFirstName as firstname',
'tm_users.sLastName as lastname',
'tm_users.sEmail as email',
'tm_users.sPhone as phone',
'tm_users_detail.sLatitude as latitude',
'tm_users_detail.sLongitude as longitude',
DB::raw('(SELECT tm_provinsi.sProvinsi FROM tm_provinsi WHERE tm_provinsi.nID = tm_users_detail.nIDProvinsi LIMIT 1) AS provinsi'),
DB::raw('(SELECT tm_kota.sKota FROM tm_kota WHERE tm_kota.nID = tm_users_detail.nIDKota LIMIT 1) AS kota'),
DB::raw('(SELECT tm_kecamatan.sKecamatan FROM tm_kecamatan WHERE tm_kecamatan.nID = tm_users_detail.nIDKecamatan LIMIT 1) AS kecamatan'),
DB::raw('(SELECT tm_kelurahan.sKelurahan FROM tm_kelurahan WHERE tm_kelurahan.nID = tm_users_detail.nIDKelurahan LIMIT 1) AS kelurahan'),
DB::raw('(SELECT tm_kelurahan.nKodePos FROM tm_kelurahan WHERE tm_kelurahan.nID = tm_users_detail.nIDKelurahan LIMIT 1) AS kode_pos')
)
->first();
if (!$pasien) {
return ApiResponse::apiResponse('Not Found', [], 'Patient not found', 404);
}
if(!$pasien->email)
{
return ApiResponse::apiResponse('Not Found', [], 'Email Patient not found', 404);
}
if(!$pasien->phone)
{
return ApiResponse::apiResponse('Not Found', [], 'Phone Patient not found', 404);
}
// Use GrabHelper to handle the API calls
$grabHelper = new GrabHelper();
$token = $grabHelper->getToken();
$serviceType = 'INSTANT';
$body = json_encode([
"merchantOrderID" => $prescriptions->merchantOrderID,
"serviceType" => $serviceType,
"vehicleType" => "BIKE",
"codType" => "REGULAR",
"paymentMethod" => "CASHLESS",
"highValue" => false,
"packages" => $packages,
"origin" => [
"address" => $apotek->alamat_apotek,
"coordinates" => [
"latitude" => (float)$apotek->lat,
"longitude" => (float)$apotek->lng
]
],
"destination" => [
"address" => "{$pasien->provinsi}, {$pasien->kota}, {$pasien->kecamatan}, {$pasien->kelurahan}, {$pasien->kode_pos}",
"coordinates" => [
"latitude" => (float)$pasien->latitude,
"longitude" => (float)$pasien->longitude
]
],
"recipient" => [
"firstName" => $pasien->firstname,
"lastName" => $pasien->lastname,
"email" => $pasien->email,
"phone" => $grabHelper->normalizePhoneNumber($pasien->phone),
"smsEnabled" => true
],
"sender" => [
"firstName" => env('SENDER_NAME_GRAB'),
"companyName" => env('SENDER_COMPANY_NAME_GRAB'),
"email" => env('SENDER_EMAIL_GRAB'),
"phone" => env('SENDER_PHONE_GRAB'),
"smsEnabled" => true
],
"schedule" => $grabHelper->getScheduleTimes()
]);
// Create the delivery request
$response = $grabHelper->createDelivery($token, $body);
$data_grab = json_decode($response, true);
// Transaction to update status
DB::connection('oldlms')->beginTransaction();
//insert to api logs
$data_logs = [
'sType' => 'out',
'sContext' => 'grab',
'sTarget' => 'deliveries/create-grab',
'sRequest' => $body,
'sResponse' => $response,
'sCreateBy' => auth()->user()->id,
'dCreateOn' => now(),
];
DB::connection('oldlms')->table('api_logs')
->insert($data_logs);
DB::connection('oldlms')->table('tx_prescription_orders')
->where('tx_prescription_orders.nID', '=', $id)
->update([
'nDeliveryID' => $data_grab['deliveryID'],
'sDeliveryStatus' => $data_grab['status'],
'sStatus' => 'waiting_for_courir',
'sUpdateBy' => auth()->user()->id,
'dUpdateOn' => now(),
]);
//insert to delivery order
$tm_delivery_statuses = DB::connection('oldlms')->table('tm_delivery_statuses')
->where('tm_delivery_statuses.sStatus', 'LIKE', '%' . $data_grab['status'] . '%')
->where('tm_delivery_statuses.nIDDelivery', '=', 3)
->select('tm_delivery_statuses.sStatusDescription')
->first();
$data_delivery_orders = [
'nIDPrescriptionOrder' => $id,
'sUUID' => $this->generateUuid($id),
'nIDDelivery' => 3, //grab
'sType' => $serviceType,
'nOrderID' => $data_grab['deliveryID'],
'nVehicleTypeID' => null,
'sCreatedDateTime' => $data_grab['schedule']['pickupTimeFrom'],
'sFinishDateTime' => $data_grab['schedule']['pickupTimeTo'],
'sStatus' => $data_grab['status'],
'sStatusDescription' => $tm_delivery_statuses->sStatusDescription,
'sMatter' => 'medicine',
'nTotalWeightKg' => 0,
'nPaymentAmount' => $data_grab['quote']['amount'],
'nDeliveryFeeAmount' => $data_grab['quote']['amount'],
'sPaymentMethod' => 'cash',
'sCreateBy' => auth()->user()->id,
'dCreateOn' => now(),
];
// Use insertGetId to insert the data and get the last inserted ID
$lastInsertId = DB::connection('oldlms')->table('tx_delivery_orders')->insertGetId($data_delivery_orders);
$data_points = [
'origin' => [
'nIDDeliveryOrder' => $lastInsertId,
'sUUID' => $this->generateUuid($lastInsertId),
'nDeliveryID' => $data_grab['deliveryID'],
'nPointID' => 1,
'nType' => 1,
'sAddress' => $data_grab['quote']['origin']['address'],
'nLatitude' => $data_grab['quote']['origin']['coordinates']['latitude'] ?? null,
'nLongitude' => $data_grab['quote']['origin']['coordinates']['longitude'] ?? null,
'sName' => $data_grab['sender']['companyName'],
'sPhone' => $data_grab['sender']['phone'],
'sTrackingUrl' => null,
'sCreateBy' => auth()->user()->id,
'dCreateOn' => now(),
],
'destination' => [
'nIDDeliveryOrder' => $lastInsertId,
'sUUID' => $this->generateUuid($lastInsertId),
'nDeliveryID' => $data_grab['deliveryID'],
'nPointID' => 2,
'nType' => 2,
'sAddress' => $data_grab['quote']['destination']['address'],
'nLatitude' => $data_grab['quote']['destination']['coordinates']['latitude'] ?? null,
'nLongitude' => $data_grab['quote']['destination']['coordinates']['longitude'] ?? null,
'sName' => $data_grab['recipient']['firstName'] . " " . $data_grab['recipient']['lastName'],
'sPhone' => $data_grab['recipient']['phone'],
'sTrackingUrl' => null,
'sCreateBy' => auth()->user()->id,
'dCreateOn' => now(),
]
];
foreach ($data_points as $value_point) {
DB::connection('oldlms')->table('tx_delivery_order_points')->insert($value_point);
}
DB::connection('oldlms')->commit();
// Return success response
return ApiResponse::apiResponse("Success", $data_grab, trans('Message.success'), 200);
} catch (\Exception $e) {
// Rollback transaction on error
DB::connection('oldlms')->rollBack();
return ApiResponse::apiResponse('Server Error', [], $e->getMessage(), 500);
}
}
/**
* Remove the specified resource from storage.
* @param int $id
* @return Renderable
*/
public function destroy($id)
{
//
}
public function generateUuid($id_prescription_order)
{
// Define the namespace (using DNS in this example)
$namespace = Uuid::NAMESPACE_DNS;
$uuidV5 = Uuid::uuid5($namespace, $id_prescription_order);
return $uuidV5->toString();
}
}

View File

@@ -7,8 +7,10 @@ use Modules\HospitalPortal\Http\Controllers\Api\MemberController;
use Modules\HospitalPortal\Http\Controllers\ClaimController;
use Modules\HospitalPortal\Http\Controllers\Api\NotificationController;
use Modules\HospitalPortal\Http\Controllers\Api\RequestLogController;
use Modules\HospitalPortal\Http\Controllers\ApotekController;
use Modules\HospitalPortal\Http\Middleware\Authentication;
use Modules\HospitalPortal\Http\Middleware\Authorization;
use Modules\Internal\Http\Controllers\Api\NavigationController;
/*
|--------------------------------------------------------------------------
@@ -36,6 +38,10 @@ Route::prefix('v1')->group(function() {
Route::middleware('auth:sanctum')->group(function () {
// Navigation
Route::get('navigations', [NavigationController::class, 'index']);
Route::post('logout', [AuthController::class, 'logout'])->name('logout');
Route::get('/user', function (Request $request) {
return $request->user();
@@ -66,6 +72,9 @@ Route::prefix('v1')->group(function() {
//Set read notification
Route::post('set-read-notification', 'setReadNotification');
});
Route::get('get-prescription-orders',[ApotekController::class, 'index']);
Route::put('put-prescription-orders/{id}',[ApotekController::class, 'update']);
Route::put('put-driver-prescription-orders/{id}',[ApotekController::class, 'getDriver']);
});
// Request Final LOG
Route::controller(RequestLogController::class)->group(function () {

View File

@@ -26,7 +26,14 @@ class PrescriptionController extends Controller
{
// return $request->toArray();
$prescription = Prescription::query()
->with(['livechat', 'user', 'items']);
->with(['livechat', 'user', 'items'])
->join('tx_prescription_orders', 'tx_prescriptions.nID', '=', 'tx_prescription_orders.nIDPrescription')
->select(
'tx_prescriptions.*',
'tx_prescription_orders.sStatus as status_prescription',
'tx_prescription_orders.sAddress as kirim_ke',
'tx_prescription_orders.sDeliveryMethod as delivery',
);
if ($request->has('search')) {
$search = $request->search;
$prescription->where(function ($query) use ($search) {
@@ -34,13 +41,12 @@ class PrescriptionController extends Controller
->orWhere('sKodeResep', 'LIKE', '%' . $search . "%");
});
}
if (($request->has('prescription_start') || $request->has('prescription_end'))
&& !empty($request->prescription_start)
&& !empty($request->prescription_end)
) {
$prescription = $prescription->where(function($q) use ($request) {
$q->where('dTanggalResep', '>=', $request->prescription_start)
->where('dTanggalResep', '<=', $request->prescription_end);
@@ -156,6 +162,7 @@ class PrescriptionController extends Controller
'Date Consultation',
'Patient',
'Doctor',
'Status',
'Jenis Obat (Drugs)',
'Jumlah Obat (QTY)',
'Cara Minum Obat',
@@ -178,7 +185,7 @@ class PrescriptionController extends Controller
});
}
if ($request->has('prescription_start') && $request->has('prescription_end') &&
if ($request->has('prescription_start') && $request->has('prescription_end') &&
!empty($request->prescription_start) && !empty($request->prescription_end)) {
$prescriptionQuery->whereBetween('dTanggalResep', [$request->prescription_start, $request->prescription_end]);
}

View File

@@ -88,8 +88,8 @@ class LivechatController extends Controller
}
})
->orderBy('nID', 'desc')
->get(['nID', 'nIDUser', 'dRequestTime', 'dAcceptTime', 'dStartTime', 'dEndTime', 'nIDDokter', 'nIDHealthCare', 'nIDAppointment', 'sStatus', 'sMediaDokter', 'sMedia', 'dCreateOn']);
->get(['nID', 'nIDUser', 'nIDDokter', 'nIDHealthCare', 'nIDAppointment', 'sStatus', 'sMediaDokter', 'sMedia', 'dCreateOn']);
$headers = [
['value' => 'No', 'cell' => 'A1', 'mergeCell' => true, 'mergeToCell' => 'A2'],
['value' => 'Kode TC', 'cell' => 'B1', 'mergeCell' => true, 'mergeToCell' => 'B2'],
@@ -150,18 +150,18 @@ class LivechatController extends Controller
$nIDUser = $liveChat->user->nIDUser ?? 0; // Principal or Dependent
$paymentMethod = $liveChat->appointment ? Helper::sPaymentMethod($liveChat->appointment->sPaymentMethod) : 'N/A';
$fullNameDoctor = '-';
if ($liveChat->doctor->user !== null) {
if (!empty($liveChat->doctor->user)) {
$fullNameDoctor = '';
if ($liveChat->doctor->user->detail !== null) {
if ($liveChat->doctor->user->detail->sTitlePrefix !== null) {
$fullNameDoctor .= $liveChat->doctor->user->detail->sTitlePrefix . '. ';
}
if ($liveChat->doctor->user->full_name !== null) {
$fullNameDoctor .= $liveChat->doctor->user->full_name . ' ';
}
if ($liveChat->doctor->user->detail->sTitleSuffix !== null) {
$fullNameDoctor .= $liveChat->doctor->user->detail->sTitleSuffix;
}
@@ -171,7 +171,7 @@ class LivechatController extends Controller
$recordType = 'P';
if ($nIDUser){
$recordType = 'D';
}
}
switch ($status) {
case 0:
$statusLivechat = "Request TC";

View File

@@ -54,6 +54,7 @@ class NavigationController extends Controller
'permission' => $child['permission'],
];
}, $navItem['children']),
'icon' => $navItem['icon'],
'permission' => $navItem['permission'],
];
}, $navigationMaster)

View File

@@ -48,6 +48,8 @@ class OrganizationController extends Controller
public function store(Request $request)
{
$organization = [
'phone' => $request->no_hp,
'email' => $request->email,
'code' => $request->code,
'name' => $request->name,
'type' => 'hospital',
@@ -119,6 +121,8 @@ class OrganizationController extends Controller
$update_organization = Organization::find($id);
$update_organization->update([
'phone' => $request->no_hp,
'email' => $request->email,
'code' => $request->code,
'name' => $request->name,
'type' => 'hospital',
@@ -152,7 +156,7 @@ class OrganizationController extends Controller
'lat' => $request->lat,
'lng' => $request->lng,
]);
$update_organization->main_address_id = $newAddres->id;
$update_organization->save();

View File

@@ -3,6 +3,8 @@
namespace Modules\Internal\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Models\Organization;
use App\Models\CorporateManager;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
@@ -110,14 +112,30 @@ class UserManagementController extends Controller
return response()->json($data);
}
public function list_organization(Request $request)
{
$query = Organization::where('type', 'hospital')->get();
$data = [
'data' => $query
];
return response()->json($data);
}
public function store_access(Request $request){
$user = User::create([
'email' => $request->email,
'username' => $request->username,
'role_id' => $request->roles,
'organization_id' => !empty($request->organizations) ? $request->organizations : null ,
'password' => Hash::make($request->password),
]);
if ($request->corporates){
CorporateManager::create([
'user_id' => $user->id,
'corporate_id' => $request->corporates
]);
}
$person = Person::updateOrCreate(
[
'id' => $user->person_id
@@ -164,6 +182,7 @@ class UserManagementController extends Controller
$userAccess->email = $request->email;
$userAccess->username = $request->username;
$userAccess->role_id = $request->roles;
$userAccess->organization_id = $request->organizations;
if ($request->password){
$userAccess->password = Hash::make($request->password);

View File

@@ -50,6 +50,7 @@ use Modules\Internal\Http\Controllers\Api\LaboratoriumResultController;
use Modules\Internal\Http\Controllers\Api\CorporateManageController;
use Modules\Internal\Http\Controllers\Api\UserManagementController;
use Modules\Internal\Http\Controllers\ClaimEncounterController;
use Modules\Linksehat\Http\Controllers\Api\AutocompleteController;
// Report
use Modules\Internal\Http\Controllers\Api\ReportLogController;
@@ -80,9 +81,12 @@ Route::prefix('internal')->group(function () {
Route::get('diagnosis', [RequestLogController::class, 'diagnosis']);
Route::get('drugs', [DrugController::class, 'drugList']);
Route::get('units', [DrugController::class, 'unitList']);
Route::get('cekphp', [RequestLogController::class, 'cekphp']);
Route::get('drugs', [AutocompleteController::class, 'drugList']);
Route::get('units', [AutocompleteController::class, 'unitList']);
Route::get('signa', [AutocompleteController::class, 'signaList']);
Route::post('signa-add', [AutocompleteController::class, 'signaAdd']);
@@ -395,6 +399,7 @@ Route::prefix('internal')->group(function () {
Route::get('user/access/{id}', [UserManagementController::class, 'edit_access']);
Route::put('user/access/{id}', [UserManagementController::class, 'update_access']);
Route::get('role-list', [UserManagementController::class, 'list_role']);
Route::get('organization-list', [UserManagementController::class, 'list_organization']);
// Navigation
Route::get('navigations', [NavigationController::class, 'index']);

View File

@@ -27,12 +27,14 @@ class OrganizationResource extends JsonResource
}
$corporatePartner = implode(', ', $corporateName);
}
}
}
$organization = [
'id' => $this->id,
'name' => $this->name,
'type' => $this->type,
'no_hp' => $this->phone,
'email' => $this->email,
'code' => $this->code,
'description' => $this->description,
'kodeRs' => $this->meta->KodeRS ?? null,

View File

@@ -16,7 +16,6 @@ class ReportPrescriptionResource extends JsonResource
public function toArray($request)
{
$patientName = $this->user ? $this->user->sFirstName .' '. $this->user->sLastName : '-';
$data = [
'id' => $this->nID,
'patient_name' => $patientName,
@@ -25,6 +24,7 @@ class ReportPrescriptionResource extends JsonResource
'date_consultation' => $this->dTanggalResep ? Carbon::parse($this->dTanggalResep)->format('Y-m-d H:i:s') : null,
'doctor_name' => $this->sDokterName ? $this->sDokterName : '-',
'items' => $this->items ? $this->items : [],
'status_prescription' => $this->status_prescription
];
return $data;

View File

@@ -111,18 +111,23 @@ class AutocompleteController extends Controller {
return Helper::responseJson(data: $manipulatedIcds);
}
public function drugList(Request $request){
$drugs = Drug::query()
->where([
'atc_code' => 'lms', // ini untuk menggunakan list obat yang baru
'atc_code' => $request->provider, // 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
'value' => $drug->id,
'label' => $drug->name,
'code' => $drug->code,
'price' => $drug->price,
'unit' => $drug->unit,
];
});
return Helper::responseJson(data: $manipulatedDrugs);
@@ -142,5 +147,38 @@ class AutocompleteController extends Controller {
return Helper::responseJson(data: $manipulatedUnits);
}
public function signaList(Request $request){
$signa = DB::connection('oldlms')->table('tm_signa')->get()->toArray();
$data = [];
if ($signa){
$temp = [];
foreach($signa as $d){
$temp['id'] = $d->nID;
$temp['value'] = $d->signa;
$temp['label'] = $d->signa;
array_push($data, $temp);
}
}
return Helper::responseJson($data);
}
public function signaAdd(Request $request){
$validatedData = $request->validate([
'signa' => 'required|string|max:255',
]);
// Insert the new signa into the tm_signa table
DB::connection('oldlms')->table('tm_signa')->insert([
'sStatusPernikahan' => $validatedData['signa']
]);
// Return a success response
return Helper::responseJson(['message' => 'Signa added successfully']);
}
}

View File

@@ -21,6 +21,10 @@ class Organization extends Model
'corporate_id_partner',
'phone',
'email',
'operational_day',
'operational_hour',
'operational_day_other',
'operational_hour_other',
];
// public $with = [

View File

@@ -25,6 +25,7 @@ class User extends Authenticatable
protected $connection = 'mysql';
protected $fillable = [
'organization_id',
'person_id',
'name',
'email',

11983
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +0,0 @@
<?php
return [
'server_key' => env('FCM_SERVER_KEY'),
];

View File

@@ -281,7 +281,27 @@ class NavigationSeeder extends Seeder
]
],
'permission' => 'user-management-client-portal'
]
],
####################### HOSPITAL PORTAL #########################
[
'title' => 'Dashboard',
'path' => '/dashboard',
'icon' => 'dashboard',
'permission' => 'dashboard-hospital-portal'
],
[
'title' => 'Claim',
'path' => '/claim',
'icon' => 'ic_booking',
'permission' => 'dashboard-claim-hospital-portal'
],
####################### CS LMS & APOTEK PORTAL #########################
[
'title' => 'Dashboard',
'path' => '/prescription-orders',
'icon' => 'dashboard',
'permission' => 'dashboard-apotek-portal'
],
];
foreach ($menuItems as $menuItemData) {
@@ -292,6 +312,7 @@ class NavigationSeeder extends Seeder
[
'title' => $menuItemData['title'],
'path' => $menuItemData['path'] ?? null,
'icon' => $menuItemData['icon'] ?? null,
'permission' => $menuItemData['permission'] ?? null
]);
@@ -304,6 +325,7 @@ class NavigationSeeder extends Seeder
[
'title' => $childData['title'],
'path' => $childData['path'] ?? null,
'icon' => $childData['icon'] ?? null,
'parent_id' => $menuItem->id,
'permission' => $childData['permission'] ?? null
]);

View File

@@ -89,14 +89,27 @@ class PermissionTableSeeder extends Seeder
'service-monitoring-limit-client-portal',
'user-management-client-portal',
'user-role-list-client-portal',
'user-access-list-client-portal'
'user-access-list-client-portal',
'file-billing-client-portal',
'file-diagnosis-client-portal',
'file-pendukung-medis-client-portal',
'benefit-client-portal',
]
]
],
####################### HOSPITAL PORTAL #########################
[
'type' => 'hospital-portal',
'datas' => [
'dashboard-hospital-portal',
'dashboard-claim-hospital-portal',
'dashboard-apotek-portal',
]
],
];
foreach ($permissions as $values) {
foreach ($values['datas'] as $value) {
Permission::updateOrCreate(['name' => $value],
Permission::updateOrCreate(['name' => $value, 'guard_name' => $values['type']],
[
'name' => $value,
'guard_name' => $values['type']

View File

@@ -5,5 +5,5 @@ PORT=8083
REACT_APP_HOST_API_URL="https://aso-api.linksehat.dev/api/client"
# VITE_API_URL="https://aso-api.linksehat.dev/api/client"
VITE_API_URL="http://localhost:8000/api/client"
VITE_API_URL="https://aso-api.linksehat.dev/api/client"

View File

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

View File

@@ -219,7 +219,16 @@ export default function ServiceMonitoring() {
};
const nameToCheck = 'service-monitoring-limit-client-portal';
const fileBillingCheck = 'file-billing-client-portal';
const fileDiagnosisCheck = 'file-diagnosis-client-portal';
const filePendukungCheck = 'file-pendukung-medis-client-portal';
const benefitCheck = 'benefit-client-portal';
const doesNameExist = checkIfNameExists(nameToCheck);
const viewfileBilling = checkIfNameExists(fileBillingCheck);
const viewfileDiagnosis = checkIfNameExists(fileDiagnosisCheck);
const viewfilePendukungCheck = checkIfNameExists(filePendukungCheck);
const viewBenefitCheck = checkIfNameExists(benefitCheck);
const navigate = useNavigate();
const controller = new AbortController();
@@ -283,6 +292,8 @@ export default function ServiceMonitoring() {
const formatNumber = (number) => {
return new Intl.NumberFormat('id-ID').format(number);
};
console.log(viewfileBilling, 'test')
const LimitPlanCard = ({ title, current, total }) => (
<Card variant="outlined" sx={{ minWidth: 200, m: 1 }}>
<CardContent>
@@ -581,6 +592,37 @@ export default function ServiceMonitoring() {
(
data.files.result.map((file, index) =>
(
file.type == 'final-log-result' && viewfilePendukungCheck ?
(
<Stack direction="column" spacing={2} key={index}>
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
<a
href={file.url}
download={file.original_name ? file.original_name : 'test'}
style={{ cursor: 'pointer', textDecoration: 'none', color: '#19BBBB' }}
target="_blank"
>
<Typography variant="body2" gutterBottom>{file.original_name ? file.original_name : '-'}</Typography>
</a>
</Stack>
</Stack>
) :
file.type == 'final-log-diagnosis' && viewfileDiagnosis ?
(
<Stack direction="column" spacing={2} key={index}>
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
<a
href={file.url}
download={file.original_name ? file.original_name : 'test'}
style={{ cursor: 'pointer', textDecoration: 'none', color: '#19BBBB' }}
target="_blank"
>
<Typography variant="body2" gutterBottom>{file.original_name ? file.original_name : '-'}</Typography>
</a>
</Stack>
</Stack>
) :
file.type == 'final-log-kondisi' && viewfileBilling ?
(
<Stack direction="column" spacing={2} key={index}>
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
@@ -595,6 +637,7 @@ export default function ServiceMonitoring() {
</Stack>
</Stack>
)
: ''
)
)
) : (
@@ -749,163 +792,171 @@ export default function ServiceMonitoring() {
</Typography>
</Grid>
</Grid>
<Grid item container spacing={1.5}>
<Grid item>
<Typography variant="subtitle2" color={'grey.600'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Benefits'}
</Typography>
</Grid>
<Grid item container>
{viewBenefitCheck ? (
<Grid item container spacing={1.5}>
<Grid item>
{loading ? (
<Skeleton animation="wave" width={300} />
) : data && data.benefits && data.benefits.length > 0 ? (
data.benefits.map((benefitValue, benefitIndex) => (
<List
subheader={
<ListSubheader>
<Typography variant="subtitle2" color={'grey.700'}>
{benefitIndex + 1 + `. ` + benefitValue.name}
</Typography>
</ListSubheader>
}
key={benefitIndex}
>
<ListItem sx={{ paddingLeft: 4 }}>
<ListItemText>
<Typography
variant="subtitle2"
color={'grey.900'}
component={'div'}
display="flex"
alignItems={'center'}
gap={1}
>
<CircleIcon sx={{ width: 8 }} />
Amount Incurred : Rp. {fSplit(benefitValue.amountIncurred)}
</Typography>
</ListItemText>
</ListItem>
<ListItem sx={{ paddingLeft: 4 }}>
<ListItemText>
<Typography
variant="subtitle2"
color={'grey.900'}
component={'div'}
display="flex"
alignItems={'center'}
gap={1}
>
<CircleIcon sx={{ width: 8 }} />
Amount Approved : Rp {fSplit(benefitValue.amountApproved)}
</Typography>
</ListItemText>
</ListItem>
<ListItem sx={{ paddingLeft: 4 }}>
<ListItemText>
<Typography
variant="subtitle2"
color={'grey.900'}
component={'div'}
display="flex"
alignItems={'center'}
gap={1}
>
<CircleIcon sx={{ width: 8 }} />
Amount Not Approved : Rp {fSplit(benefitValue.amountNotAprroved)}
</Typography>
</ListItemText>
</ListItem>
<ListItem sx={{ paddingLeft: 4 }}>
<ListItemText>
<Typography
variant="subtitle2"
color={'grey.900'}
component={'div'}
display="flex"
alignItems={'center'}
gap={1}
>
<CircleIcon sx={{ width: 8 }} />
Excess Paid : Rp {fSplit(benefitValue.excessPaid)}
</Typography>
</ListItemText>
</ListItem>
<ListItem sx={{ paddingLeft: 4 }}>
<ListItemText>
<Typography
variant="subtitle2"
color={'grey.900'}
component={'div'}
display="flex"
alignItems={'center'}
gap={1}
>
<CircleIcon sx={{ width: 8 }} />
Description : {benefitValue.description}
</Typography>
</ListItemText>
</ListItem>
</List>
))
) : (
<Typography variant="subtitle1" color={'grey.800'}>
-
</Typography>
)}
<Typography variant="subtitle2" color={'grey.600'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Benefits'}
</Typography>
</Grid>
<Grid item container>
<Grid item>
{loading ? (
<Skeleton animation="wave" width={300} />
) : data && data.benefits && data.benefits.length > 0 ? (
data.benefits.map((benefitValue, benefitIndex) => (
<List
subheader={
<ListSubheader>
<Typography variant="subtitle2" color={'grey.700'}>
{benefitIndex + 1 + `. ` + benefitValue.name}
</Typography>
</ListSubheader>
}
key={benefitIndex}
>
<ListItem sx={{ paddingLeft: 4 }}>
<ListItemText>
<Typography
variant="subtitle2"
color={'grey.900'}
component={'div'}
display="flex"
alignItems={'center'}
gap={1}
>
<CircleIcon sx={{ width: 8 }} />
Amount Incurred : Rp {fSplit(benefitValue.amountApproved)}
</Typography>
</ListItemText>
</ListItem>
<ListItem sx={{ paddingLeft: 4 }}>
<ListItemText>
<Typography
variant="subtitle2"
color={'grey.900'}
component={'div'}
display="flex"
alignItems={'center'}
gap={1}
>
<CircleIcon sx={{ width: 8 }} />
Amount Approved : Rp {fSplit(benefitValue.amountApproved)}
</Typography>
</ListItemText>
</ListItem>
<ListItem sx={{ paddingLeft: 4 }}>
<ListItemText>
<Typography
variant="subtitle2"
color={'grey.900'}
component={'div'}
display="flex"
alignItems={'center'}
gap={1}
>
<CircleIcon sx={{ width: 8 }} />
Amount Not Approved : Rp {fSplit(benefitValue.amountNotAprroved)}
</Typography>
</ListItemText>
</ListItem>
<ListItem sx={{ paddingLeft: 4 }}>
<ListItemText>
<Typography
variant="subtitle2"
color={'grey.900'}
component={'div'}
display="flex"
alignItems={'center'}
gap={1}
>
<CircleIcon sx={{ width: 8 }} />
Excess Paid : Rp {fSplit(benefitValue.excessPaid)}
</Typography>
</ListItemText>
</ListItem>
<ListItem sx={{ paddingLeft: 4 }}>
<ListItemText>
<Typography
variant="subtitle2"
color={'grey.900'}
component={'div'}
display="flex"
alignItems={'center'}
gap={1}
>
<CircleIcon sx={{ width: 8 }} />
Description : {benefitValue.description}
</Typography>
</ListItemText>
</ListItem>
</List>
))
) : (
<Typography variant="subtitle1" color={'grey.800'}>
-
</Typography>
)}
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item container spacing={1.5}>
<Grid item>
<Typography variant="subtitle2" color={'grey.600'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Benefits Total'}
</Typography>
) : ('')
}
{viewBenefitCheck ? (
<Grid item container spacing={1.5}>
<Grid item>
<Typography variant="subtitle2" color={'grey.600'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Benefits Total'}
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="subtitle1" color={'grey.800'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Total Incurred : Rp. '}
{loading ? (
<Skeleton animation={'wave'} width={300} />
) : data && data.benefitTotal ? (
fSplit(data.benefitTotal.totalIncurred)
) : (
'-'
)}
</Typography>
<Typography variant="subtitle1" color={'grey.800'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Total Approve : Rp. '}
{loading ? (
<Skeleton animation={'wave'} width={300} />
) : data && data.benefitTotal ? (
fSplit(data.benefitTotal.totalApprove)
) : (
'-'
)}
</Typography>
<Typography variant="subtitle1" color={'grey.800'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Total Not Approve : Rp.'}
{loading ? (
<Skeleton animation={'wave'} width={300} />
) : data && data.benefitTotal ? (
fSplit(data.benefitTotal.totalNotApprove)
) : (
'-'
)}
</Typography>
<Typography variant="subtitle1" color={'grey.800'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Total Excess : Rp.'}
{loading ? (
<Skeleton animation={'wave'} width={300} />
) : data && data.benefitTotal ? (
fSplit(data.benefitTotal.totalExcess)
) : (
'-'
)}
</Typography>
</Grid>
</Grid>
<Grid item xs={12}>
<Typography variant="subtitle1" color={'grey.800'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Total Incurred : Rp. '}
{loading ? (
<Skeleton animation={'wave'} width={300} />
) : data && data.benefitTotal ? (
fSplit(data.benefitTotal.totalIncurred)
) : (
'-'
)}
</Typography>
<Typography variant="subtitle1" color={'grey.800'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Total Approve : Rp. '}
{loading ? (
<Skeleton animation={'wave'} width={300} />
) : data && data.benefitTotal ? (
fSplit(data.benefitTotal.totalApprove)
) : (
'-'
)}
</Typography>
<Typography variant="subtitle1" color={'grey.800'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Total Not Approve : Rp.'}
{loading ? (
<Skeleton animation={'wave'} width={300} />
) : data && data.benefitTotal ? (
fSplit(data.benefitTotal.totalNotApprove)
) : (
'-'
)}
</Typography>
<Typography variant="subtitle1" color={'grey.800'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Total Excess : Rp.'}
{loading ? (
<Skeleton animation={'wave'} width={300} />
) : data && data.benefitTotal ? (
fSplit(data.benefitTotal.totalExcess)
) : (
'-'
)}
</Typography>
</Grid>
</Grid>
<Grid item container xs={12} spacing={1.5}>
) : ('')}
<Grid item container xs={12} spacing={1.5}>
<Grid item xs={12}>
<Typography variant="subtitle2" color={'grey.600'}>
{loading ? <Skeleton animation={'wave'} width={200} /> : 'Hospital'}

View File

@@ -1,6 +1,8 @@
export type Organizations = {
id: number;
code: string;
no_hp: number;
email: string;
name: string;
address: string;
type: string;

View File

@@ -134,6 +134,16 @@ export type Role = {
permissions: number[]
};
export type Organization = {
id: number;
name: string;
};
export type Corporate = {
id: number;
name: string;
};
export type Permisions = {
name: string;
guard_name: string;
@@ -146,6 +156,8 @@ export type UserAccess = {
email: string;
person: Person;
role: Role;
organization_id: Organization;
corporate_id: Corporate;
}
export type Person = {

View File

@@ -116,6 +116,8 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
name: currentOrganizations?.name || '',
code: currentOrganizations?.code || '',
phone: currentOrganizations?.phone || '',
no_hp: currentOrganizations?.no_hp || '',
email: currentOrganizations?.email || '',
lat: currentOrganizations?.lat || '',
lng: currentOrganizations?.lng || '',
address: currentOrganizations?.address || '',
@@ -185,6 +187,8 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
formData.append('name', data.name);
formData.append('code', data.code);
formData.append('phone', data.phone);
formData.append('no_hp', data.no_hp);
formData.append('email', data.email);
formData.append('lat', data.lat);
formData.append('lng', data.lng);
formData.append('address', data.address);
@@ -361,7 +365,7 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
const findValueCorporate = selectedCorporatID.find(
(item: any) => item.value === currentOrganizations?.corporate_id_partner
);
return (
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
<Stack spacing={3}>
@@ -391,6 +395,14 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
<LabelStyle>Nomor IGD</LabelStyle>
<RHFTextField name="phone" placeholder="Tuliskan No IGD" />
</Grid>
<Grid item xs={12} md={6}>
<LabelStyle>No. HP</LabelStyle>
<RHFTextField name="no_hp" placeholder="Tuliskan No. HP" />
</Grid>
<Grid item xs={12} md={6}>
<LabelStyle>Email</LabelStyle>
<RHFTextField name="email" placeholder="Tuliskan Email" />
</Grid>
<Grid item xs={12}>
<LabelStyle>Alamat</LabelStyle>
<RHFTextField name="address" placeholder="Tuliskan Alamat" />

View File

@@ -301,9 +301,21 @@ export default function List() {
<Grid item xs={10}>
: {row.code ? row.code : '-'}
</Grid>
<Grid item xs={2}>
No. HP
</Grid>
<Grid item xs={10}>
: {row.no_hp ? row.no_hp : '-'}
</Grid>
<Grid item xs={2}>
Email
</Grid>
<Grid item xs={10}>
: {row.email ? row.email : '-'}
</Grid>
<Grid item xs={2}>
Rekanan
Rekanan
</Grid>
<Grid item xs={10}>
: {row.corporate_name ? row.corporate_name : '-'}

View File

@@ -158,7 +158,6 @@ export default function List() {
setSearchText(searchParams.get('search') ?? '');
}, []);
return (
<form style={{ width: '100%' }}>
@@ -337,6 +336,7 @@ export default function List() {
<TableCell align="left">{row.date_consultation ? fDateTime(row.date_consultation) : '-'}</TableCell>
<TableCell align="left">{row.patient_name ?? '-'}</TableCell>
<TableCell align="left">{row.doctor_name ?? '-'}</TableCell>
<TableCell align="left">{row.status_prescription ?? '-'}</TableCell>
{/* <TableCell align="center">
<ButtonGroup variant="text" aria-label="text button group">
<Link to={'/report/appointments/' + row.id + '/show'}>
@@ -390,7 +390,7 @@ export default function List() {
</Collapse>
</TableCell>
</TableRow>
{/* END COLLAPSIBLE ROW */}
<Dialog
@@ -542,6 +542,9 @@ export default function List() {
<TableCell style={headStyle} align="left">
Doctor
</TableCell>
<TableCell style={headStyle} align="left">
Status
</TableCell>
{/* <TableCell style={headStyle} align="center">
Aksi
</TableCell> */}

View File

@@ -6,6 +6,7 @@ import {useContext, useEffect, useMemo, useState } from 'react';
import axios from '../../../utils/axios';
import UserAccessForm from './Form';
import { Role, UserAccess } from '../../../@types/user';
import Organizations from "@/pages/Master/Hospitals/Index";
@@ -13,6 +14,8 @@ export default function UserAccessCreate() {
const { id } = useParams();
const [ currentUserAccess, setCurrentUserAccess ] = useState<UserAccess>();
const [ roles, setRole ] = useState<any>();
const [ corporate, setCorporate ] = useState<any>();
const [ organizations, setOrganization ] = useState<any>();
const navigate = useNavigate();
@@ -40,9 +43,30 @@ export default function UserAccessCreate() {
navigate('/404');
}
})
axios.get('/organization-list')
.then((res)=> {
setOrganization(res.data)
})
.catch((err) => {
if (err.response.status === 404) {
navigate('/404');
}
})
axios.get('/corporates')
.then((res)=> {
setCorporate(res.data)
})
.catch((err) => {
if (err.response.status === 404) {
navigate('/404');
}
})
}, [id]);
console.log(corporate, 'test')
return (
<Page title= "User Access">
@@ -57,7 +81,7 @@ export default function UserAccessCreate() {
]}
/>
<UserAccessForm isEdit={isEdit} currentUserAccess={currentUserAccess} roles={roles}/>
<UserAccessForm isEdit={isEdit} currentUserAccess={currentUserAccess} roles={roles} organizations={organizations} corporate={corporate} />
</Page>
);
}

View File

@@ -1,23 +1,26 @@
import * as Yup from 'yup';
import { LoadingButton } from "@mui/lab";
import { Box, Card, Grid, Stack, Typography } from "@mui/material";
import { Role, UserAccess } from "../../../@types/user";
import { FormProvider, RHFSelect, RHFSwitch, RHFTextField } from "../../../components/hook-form";
import { useEffect, useMemo } from 'react';
import { Role, UserAccess, Organization } from "../../../@types/user";
import { FormProvider, RHFSelect, RHFTextField } from "../../../components/hook-form";
import { useEffect, useMemo, useState } from 'react';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import { useSnackbar } from 'notistack';
import { useNavigate, useParams } from 'react-router-dom';
import axios from '../../../utils/axios';
import palette from '@/theme/palette';
import { Corporate } from '@/@types/corporates';
type Props = {
isEdit: boolean;
currentUserAccess?: UserAccess;
roles: Role
roles: Role;
organizations: Organization;
corporate: Corporate;
};
export default function AccsessForm({ isEdit, currentUserAccess, roles }: Props) {
export default function AccessForm({ isEdit, currentUserAccess, roles, organizations, corporate }: Props) {
const { enqueueSnackbar } = useSnackbar();
const navigate = useNavigate();
@@ -27,13 +30,14 @@ export default function AccsessForm({ isEdit, currentUserAccess, roles }: Props)
name: Yup.string().required('Name is required'),
});
console.log(currentUserAccess, 'test')
const defaultValues = useMemo(
() => ({
name: currentUserAccess?.person?.name || '',
username: currentUserAccess?.username || '',
username: currentUserAccess?.username || '',
email: currentUserAccess?.email || '',
roles: currentUserAccess?.role?.id || [],
roles: currentUserAccess?.role?.id || '',
organizations: currentUserAccess?.organization_id || '',
corporates: currentUserAccess?.corporate_id || '',
password: '',
}),
[currentUserAccess]
@@ -56,92 +60,119 @@ export default function AccsessForm({ isEdit, currentUserAccess, roles }: Props)
const {
reset,
watch,
control,
setValue,
getValues,
setError,
handleSubmit,
setError,
formState: { isSubmitting },
} = methods;
// Watch 'roles' field to conditionally render other fields
const selectedRole = watch('roles');
const onSubmit = async (data: any) => {
console.log(data);
console.log(data, 'test123');
if (!isEdit) {
await axios
.post('/user/access', data)
.then((res) => {
enqueueSnackbar('User created successfully', { variant: 'success' });
})
.then((res) => {
navigate('/user-access', { replace: true });
})
.catch(({ response }) => {
if (response.status === 422) {
for (const [key, value] of Object.entries(response.data.errors)) {
setError(key, { message: value[0] });
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
.post('/user/access', data)
.then((res) => {
enqueueSnackbar('User created successfully', { variant: 'success' });
navigate('/user-access', { replace: true });
})
.catch(({ response }) => {
if (response.status === 422) {
for (const [key, value] of Object.entries(response.data.errors)) {
setError(key, { message: value[0] });
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
}
} else {
enqueueSnackbar('Create Failed : ' + response.data.message, { variant: 'error' });
}
}
else {
enqueueSnackbar('Create Failed : '+ response.data.message, { variant: 'error' });
}
});
});
} else {
await axios
.put('/user/access/' + currentUserAccess?.id, data)
.then((res) => {
enqueueSnackbar('User updated successfully', { variant: 'success' });
})
.then((res) => {
navigate('/user-access' , { replace: true });
navigate('/user-access', { replace: true });
})
.catch(({ response }) => {
enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' });
enqueueSnackbar('Update Failed : ' + response.data.message, { variant: 'error' });
});
}
};
const optionsRoles = roles?.data?.map(item => ({
// Map role, organization, and corporate options
const optionsRoles = roles?.data?.map((item) => ({
value: item.id,
label: item.name
label: item.name,
})) ?? [];
const optionsOrganization = organizations?.data?.map((item) => ({
value: item.id,
label: item.name,
})) ?? [];
const optionsCorporate = corporate?.data?.map((item) => ({
value: item.id,
label: item.name,
})) ?? [];
if (optionsRoles.length > 0) {
optionsRoles.unshift({ value: '', label: '' });
}
return (
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
<Box sx={{ px: 2 }}>
<Grid container spacing={2}>
<Grid item xs={12} sm={12}>
<Card sx={{ px: 3, py: 4 }}>
<Stack spacing={2}>
<Typography variant="h6" color={palette.light.primary.main}>User Access</Typography>
<RHFTextField name="name" label="Name" />
<RHFTextField name="username" label="Username" />
<RHFTextField type="email" name="email" label="Email" />
<RHFTextField type="password" name="password" label="Password" />
<RHFSelect name="roles" label="Roles">
{optionsRoles.map((option, index) => (
<option key={index} value={option.value}>
{option.label}
</option>
))}
</RHFSelect>
<Box sx={{ px: 2 }}>
<Grid container spacing={2}>
<Grid item xs={12} sm={12}>
<Card sx={{ px: 3, py: 4 }}>
<Stack spacing={2}>
<Typography variant="h6" color={palette.light.primary.main}>
User Access
</Typography>
<RHFTextField name="name" label="Name" />
<RHFTextField name="username" label="Username" />
<RHFTextField type="email" name="email" label="Email" />
<RHFTextField type="password" name="password" label="Password" />
{/* Select for roles */}
<RHFSelect name="roles" label="Roles">
{optionsRoles.map((option, index) => (
<option key={index} value={option.value}>
{option.label}
</option>
))}
</RHFSelect>
<LoadingButton type="submit" variant="contained" size="large" fullWidth={true} loading={isSubmitting}>
{ isEdit? 'Update' : 'Create' }
</LoadingButton>
{/* Conditional rendering based on selectedRole */}
{selectedRole && (['8'].includes(selectedRole) ? (
<RHFSelect name="organizations" label="Organizations">
{optionsOrganization.map((option, index) => (
<option key={index} value={option.value}>
{option.label}
</option>
))}
</RHFSelect>
) : ['2'].includes(selectedRole) ? (
<RHFSelect name="corporates" label="Corporates">
{optionsCorporate.map((option, index) => (
<option key={index} value={option.value}>
{option.label}
</option>
))}
</RHFSelect>
) : null)}
</Stack>
</Card>
</Grid>
</Grid>
</Box>
</FormProvider>
<LoadingButton
type="submit"
variant="contained"
size="large"
fullWidth={true}
loading={isSubmitting}
>
{isEdit ? 'Update' : 'Create'}
</LoadingButton>
</Stack>
</Card>
</Grid>
</Grid>
</Box>
</FormProvider>
);
}

View File

@@ -33,6 +33,7 @@
"txtSubmissionDate" : "Admission Date",
"txtDataNotFound" : "Data Not Found",
"txtConditionDocument" : "Condition Document",
"txtBillingDocument" : "Billing Document",
"txtDiagnosisDokument" : "Diagnosis Dokument",
"txtSupportingResultDocument" : "Supporting Result Document",
"txtAddResult" : "Add Result",

View File

@@ -33,8 +33,9 @@
"txtSubmissionDate" : "Tanggal Masuk",
"txtDataNotFound" : "Data Tidak Ditemukan",
"txtConditionDocument" : "Dokumen Kondisi",
"txtBillingDocument" : "Dokumen Billing",
"txtDiagnosisDokument" : "Dokumen Diagnosis",
"txtSupportingResultDocument" : "Dokumen Pendukung",
"txtSupportingResultDocument" : "Dokumen Pendukung Medis",
"txtAddResult" : "Tambah Hasil",
"txtServiceType" : "Tipe Layanan",
"txtAdditionalDocuments" : "Dokumen Tambahan",

View File

@@ -25,5 +25,5 @@ export default function Logo({ disabledLink = false, sx }: Props) {
return <>{logo}</>;
}
return <RouterLink to="/">{logo}</RouterLink>;
return <RouterLink to="#">{logo}</RouterLink>;
}

View File

@@ -24,12 +24,21 @@ import {
Typography,
LinearProgress,
linearProgressClasses,
Collapse,
Divider,
IconButton,
Modal,
CircularProgress
} from '@mui/material';
import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material';
import { visuallyHidden } from '@mui/utils';
import { DatePicker, LocalizationProvider, MobileDatePicker } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { fDate, fDateSuffix, fDateTime, fDateTimeWithAge } from '../utils/formatTime';
/* ---------------------------------- axios --------------------------------- */
import axios from '../utils/axios';
/* ---------------------------------- react --------------------------------- */
@@ -50,6 +59,10 @@ import GetAppIcon from '@mui/icons-material/GetApp';
import { LanguageContext } from '@/contexts/LanguageContext';
import CancelIcon from '@mui/icons-material/Cancel';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import CloseIcon from '@mui/icons-material/Close';
import InfoIcon from '@mui/icons-material/Info';
import { enqueueSnackbar } from 'notistack';
import useAuth from '@/hooks/useAuth';
/* --------------------------------- styled --------------------------------- */
const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
@@ -79,6 +92,9 @@ export default function Table<T>({
searchs,
exportReport,
selected,
openRowId, // Receive the currently opened row ID
setOpenRowId, // Receive the function to set the opened row ID
reloadData,
}: TableListProps<T>) {
/* ------------------------------- handle sort ------------------------------ */
const handleRequestSort = async (event: React.MouseEvent<unknown>, property: string) => {
@@ -209,6 +225,114 @@ export default function Table<T>({
params.setAppliedParams(parameters);
};
/* -------------------------------------------------------------------------- */
//============================== APOTEK =======================================//
const {user} = useAuth();
const formattedRoleName = user?.role.name;
// List of statuses for 'apotek'
const allowedStatusesForApotek = ['waiting_pharmacy', 'order_prepared'];
const allowedStatusesForCSLMS = ['waiting_pharmacy', 'order_prepared', 'ready', 'waiting_for_courir', 'package_picked_up', 'package_on_delivery', 'failed'];
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(true);
const handleClick = () => {
// handleClickKonfirmasi(row); // Call the function passed from parent
setOpen(true); // Show modal
setLoading(true); // Show loading animation
// Simulate finding driver (3 seconds delay)
setTimeout(() => {
setLoading(false); // Hide loading after 3 seconds
}, 3000);
};
const [openDialogStatus, setOpenDialogStatus] = useState(false);
const [dialogIDRow, setDialogIDRow] = useState<number | null>(null);
const [dialogIDRowDriver, setDialogIDRowDriver] = useState<number | null>(null);
const [txtStatusDriver, setTxtStatusDriver] = useState('');
const [txtIDDriver, setTxtIDDriver] = useState('');
const handleClose = (row:any) => {
setDialogIDRowDriver(row.id === dialogIDRowDriver ? null : row.id);
if (reloadData) {
reloadData();
}
};
const handleCloseDialogUpdate = () => {
setOpenDialogStatus(false);
}
const handleEditDataStatus = (data: any) => {
setOpenDialogStatus(true);
}
const [isDisabled, setIsDisabled] = useState(false);
const handleClickKonfirmasi = (row: any) => {
setTxtStatusDriver('');
setTxtIDDriver('');
if(row.sStatus === 'ready' || row.sStatus === 'failed')
{
//close
setDialogIDRow(row.id === dialogIDRow ? null : row.id);
//get driver
setDialogIDRowDriver(row.id === dialogIDRowDriver ? null : row.id);
// setOpen(true); // Show modal
setLoading(true); // Show loading animation
// Simulate finding driver (3 seconds delay)
// setTimeout(() => {
// setLoading(false); // Hide loading after 3 seconds
// }, 3000);
const updateData = {
sStatus: row.sStatus
};
axios
.put(`/put-driver-prescription-orders/${row.nID_orders}`, updateData)
.then((response) => {
setTxtStatusDriver(response?.data?.data?.status);
setTxtIDDriver(response?.data?.data?.deliveryID);
setLoading(false);
// enqueueSnackbar(response?.data?.meta?.message, { variant: 'success' });
// Call reloadData to refresh the table
})
.catch((error) => {
const errorMessage = error.response?.data?.meta?.message || 'Failed to update status';
enqueueSnackbar(errorMessage, { variant: 'error' });
setLoading(false);
setIsDisabled(false); // Re-enable the button after success
});
}
else
{
putPrescriptionOrders(row);
}
}
const putPrescriptionOrders = (row: any) => {
setIsDisabled(true); // Disable button after clicking
const updateData = {
sStatus: row.sStatus
};
axios
.put(`/put-prescription-orders/${row.nID_orders}`, updateData)
.then((response) => {
enqueueSnackbar(response?.data?.meta?.message, { variant: 'success' });
setDialogIDRow(row.id === dialogIDRow ? null : row.id);
setIsDisabled(false); // Re-enable the button after success
// Call reloadData to refresh the table
if (reloadData) {
reloadData();
}
})
.catch((error) => {
const errorMessage = error.response?.data?.meta?.message || 'Failed to update status';
enqueueSnackbar(errorMessage, { variant: 'error' });
setIsDisabled(false); // Re-enable the button after success
});
}
return (
// <Card>
<Grid container>
@@ -416,6 +540,7 @@ export default function Table<T>({
</TableRow>
) : rows && rows.length >= 1 ? (
rows.map((row, rowIndex) => (
<>
<TableRow key={rowIndex}>
{!selected.useSelected ? (
''
@@ -440,6 +565,378 @@ export default function Table<T>({
</TableCell>
))}
</TableRow>
{/* COLLAPSIBLE ROW */}
<TableRow
sx={{ cursor: 'pointer' }} // Use pointer cursor always, or conditionally based on your preference
>
<TableCell colSpan={6}>
<Collapse in={openRowId === row.id} timeout="auto" unmountOnExit>
<Card sx={{padding:2}}>
{/* Icon inside a Box for spacing and alignment */}
<Stack direction="row" padding={2} justifyContent="space-between" alignItems="center">
<Stack direction="row">
<Box sx={{ display: 'flex', alignItems: 'center', marginRight: 1 }}>
<InfoIcon sx={{ color: row.sStatus == 'waiting_pharmacy' ? '#D3D3D3' : '#00E676', fontSize: 24 }} /> {/* Adjust size and color */}
</Box>
<Typography variant='subtitle2' sx={{ color: '#00E676' }}>
{row.status}
</Typography>
</Stack>
{row.nDeliveryID && (
<Box sx={{ ml: 'auto' }}>
<Typography variant='subtitle2'>
Grab Delivery ID: {row.nDeliveryID}
</Typography>
</Box>
)}
</Stack>
<Box onClick={() => {setOpenRowId(openRowId === row.id ? null : row.id);}} sx={{ padding: '20px', maxWidth: '1200px', margin: '0 auto', backgroundColor: '#ffffff', borderRadius: '8px' }}>
<Grid container spacing={2}>
{/* Row 1 */}
<Grid item xs={12} md={6}>
<Typography variant="h6" fontWeight="bold">{localeData.txtProviderDoctorInformation}</Typography>
<Grid container>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtNamaDokter} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.nama_dokter}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtSpesialisasiDokter} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.spesialis}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">SIP :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.sip}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtNoPonsel} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.no_ponsel_dokter}</strong></Typography>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={6}>
<Typography variant="h6" fontWeight="bold">{localeData.txtInformasiPasien}</Typography>
<Grid container>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtNamaPasien} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.pasien}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtTanggalLahirUmur} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.tgl_lahir_pasien && row.tgl_lahir_pasien !=='0000-00-00' ? fDateTimeWithAge(row.tgl_lahir_pasien) : ''}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtJenisKelamin} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.jenis_kelamin_pasien}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtTinggi} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.tinggi_berat}</strong></Typography>
</Grid>
</Grid>
</Grid>
{/* Divider */}
<Grid item xs={12}>
<Divider />
</Grid>
<Grid item xs={12} md={6}>
<Typography variant="h6" fontWeight="bold">{localeData.txtInformasiAsuransi}</Typography>
<Grid container>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtNomorKartu} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.no_polis}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtAsuransi} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.perusahaan_asuransi}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtPerusahaan} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.nama_perusahaan}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtTipeAsuransi} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.kode_produk}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtKelasAsuransi} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.kelas_asuransi}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtTipeMember} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.tipe_member}</strong></Typography>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={6}>
<Typography variant="h6" fontWeight="bold">{localeData.txtInformasiOrder}</Typography>
<Grid container>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtNamaPenerima} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.pasien}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtAlamatPenerima} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.alamat_penerima}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtPengiriman} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.pengiriman}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtTotal} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.total_kirim}</strong></Typography>
</Grid>
</Grid>
</Grid>
{/* Divider */}
<Grid item xs={12}>
<Divider />
</Grid>
{/* Row 2 */}
<Grid item xs={12} md={6}>
<Typography variant="h6" fontWeight="bold">{localeData.txtInformasiResep}</Typography>
<Grid container>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtNomorResep} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.no_resep}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtNomorRefDokter} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.noref_dokter}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtTanggalTerbitResep} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.tanggal}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtTanggalKedaluwarsa} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.valid_tanggal}</strong></Typography>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={6}>
<Typography variant="h6" fontWeight="bold">{localeData.txtInformasiKonsultasi}</Typography>
<Grid container>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtNomorPenjamin} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.nomor_penjamin}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtTanggalKonsultasi} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.tgl_livechat}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtAlergi} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.alergi_desc}</strong></Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">{localeData.txtDiagnosis} :</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2"><strong>{row.diagnosa}</strong></Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Box>
<Box onClick={() => {setOpenRowId(openRowId === row.id ? null : row.id);}} sx={{ padding: '20px', maxWidth: '1200px', margin: '20px auto', backgroundColor: '#ffffff', borderRadius: '8px' }}>
<TableHead>
<TableRow>
<TableCell>{localeData.txtObat}</TableCell>
<TableCell align="left">{localeData.txtSigna}</TableCell>
<TableCell align="left">{localeData.txtWaktu}</TableCell>
<TableCell align="left">{localeData.txtDurasi}</TableCell>
<TableCell align="left">{localeData.txtJumlah}</TableCell>
<TableCell align="left">{localeData.txtCatatanObat}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{row.prescription_items ?
(
row.prescription_items.map((row : any, rowIndex: any) => (
<TableRow key={rowIndex}>
<TableCell>{row.sItemName}</TableCell>
<TableCell align="left">{row.sSigna}</TableCell>
<TableCell align="left">{row.sTiming}</TableCell>
<TableCell align="left">{row.sDuration}</TableCell>
<TableCell align="left">{row.nQty}</TableCell>
<TableCell align="left">{row.sNote}</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={headCells?.length} align="center">
{localeData.txtDataNotFound}
</TableCell>
</TableRow>
)}
</TableBody>
</Box>
<Box sx={{ display: 'flex', justifyContent: 'space-between', padding: '20px', maxWidth: '1200px', margin: '0 auto' }}>
{/* Close Button on the Left */}
<Button variant="outlined" color="inherit" onClick={() => setOpenRowId(null)}>
{localeData.txtButtonClose}
</Button>
{/* Accept Button on the Right */}
{row.button_accept && formattedRoleName === 'admin-apotek' && allowedStatusesForApotek.includes(row.sStatus) ? (
<Button variant="contained" color="primary" onClick={() => setDialogIDRow(row.id === dialogIDRow ? null : row.id)}>
{row.button_accept}
</Button>
) : ''}
{row.button_accept && formattedRoleName === 'cs-lms' && allowedStatusesForCSLMS.includes(row.sStatus) ? (
<Button variant="contained" color="primary" onClick={() => setDialogIDRow(row.id === dialogIDRow ? null : row.id)}>
{row.button_accept}
</Button>
) : ''}
</Box>
{/* Dialog Update Status */}
<Dialog open={dialogIDRow === row.id} 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">{localeData.txtConfirmation}</Typography>
</Stack>
<IconButton sx={{ color: '#FFF' }} onClick={() => setDialogIDRow(row.id === dialogIDRow ? null : row.id)}>
<CloseIcon />
</IconButton>
</Stack>
</DialogTitle>
<DialogContent>
<Stack spacing={2} padding={2}>
<Typography variant='body1'>{localeData.txtDialogConfirmation}</Typography>
<Card sx={{padding:2}} >
<Stack direction='row' spacing={2}>
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '50%'}}>{localeData.txtNomorResep}</Typography>
<Typography variant='subtitle2' sx={{width: '50%'}}>{row.no_resep}</Typography>
</Stack>
<Stack direction='row' spacing={2}>
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '50%'}}>{localeData.txtTanggalTerbitResep}</Typography>
<Typography variant='subtitle2' sx={{width: '50%'}}>{row.tanggal}</Typography>
</Stack>
</Card>
</Stack>
</DialogContent>
<DialogActions>
<Button sx={{backgroundColor: '#19BBBB'}} variant="contained" onClick={() => handleClickKonfirmasi(row)} disabled={isDisabled}>{localeData.txtOK}</Button>
</DialogActions>
</Dialog>
{/* Modal for fullscreen display */}
<Modal open={dialogIDRowDriver === row.id} onClose={() => handleClose(row)}>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
// backgroundColor: 'rgba(0, 0, 0, 0.8)', // semi-transparent background
color: '#fff',
textAlign: 'center',
}}
>
{loading ? (
<>
<CircularProgress color="inherit" />
<Typography variant="h6" sx={{ mt: 2 }}>
{localeData.txtFindingDriver}
</Typography>
</>
) : (
<>
<Typography variant="h4">Info!</Typography>
<Typography variant="h6" sx={{ mt: 2 }}>
{txtIDDriver ? (
`${localeData.txtDriverFound} ${txtIDDriver} status ${txtStatusDriver}.`
) : (
// You can add an alternative UI or message here, or leave it empty
`Failed to get driver, please check the message info.`
)}
</Typography>
<Button
sx={{ mt: 4, backgroundColor: '#19BBBB' }}
variant="contained"
onClick={() => handleClose(row)}
>
{localeData.txtOK}
</Button>
</>
)}
</Box>
</Modal>
</Card>
</Collapse>
</TableCell>
</TableRow>
</>
))
) : (
<TableRow>

View File

@@ -28,26 +28,42 @@ export default function NavSectionVertical({
isCollapse = false,
...other
}: NavSectionProps) {
return (
<Box {...other}>
{navConfig.map((group, index) => (
<List key={index} disablePadding sx={{ px: 2 }}>
<ListSubheaderStyle
key={index}
sx={{
...(isCollapse && {
opacity: 0,
}),
}}
>
{group.subheader}
</ListSubheaderStyle>
return (
<Box {...other}>
{navConfig.length === 0 ? ( // Check if navConfig is empty
<List disablePadding sx={{ px: 2, display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
<ListSubheaderStyle
sx={{
...(isCollapse && {
opacity: 0,
}),
}}
>
{/* Optional: You can put a title or leave it empty */}
</ListSubheaderStyle>
<div style={{ textAlign: 'center', marginTop: '50px' }}>Loading...</div> {/* Adjust marginTop as needed */}
</List>
) : (
navConfig.map((group, index) => (
<List key={index} disablePadding sx={{ px: 2 }}>
<ListSubheaderStyle
sx={{
...(isCollapse && {
opacity: 0,
}),
}}
>
{group.subheader}
</ListSubheaderStyle>
{group.items.map((list) => (
<NavListRoot key={list.title} list={list} isCollapse={isCollapse} />
))}
</List>
))
)}
</Box>
);
{group.items.map((list) => (
<NavListRoot key={list.title} list={list} isCollapse={isCollapse} />
))}
</List>
))}
</Box>
);
}

View File

@@ -13,8 +13,14 @@ type GuestGuardProps = {
export default function GuestGuard({ children }: GuestGuardProps) {
const { isAuthenticated } = useAuth();
if (isAuthenticated) {
const {user} = useAuth();
const formattedRoleName = user?.role.name;
if((formattedRoleName === 'admin-apotek' || formattedRoleName === 'cs-lms') && isAuthenticated)
{
return <Navigate to={'/prescription-orders'} replace={true}/>;
}
if(formattedRoleName === 'hospital-admin')
{
return <Navigate to={'/dashboard'} replace={true}/>;
}

View File

@@ -1,5 +1,7 @@
import { ReactNode } from 'react';
import { Container, Alert, AlertTitle } from '@mui/material';
import useAuth from '@/hooks/useAuth';
import Page404 from '@/pages/Page404';
// ----------------------------------------------------------------------
@@ -9,9 +11,10 @@ type RoleBasedGuardProp = {
};
const useCurrentRole = () => {
// Logic here to get current user role
const role = 'admin';
return role;
// Fetch the role from useAuth
const { user } = useAuth();
const formattedRoleName = user?.role.name || ''; // Default to empty string if role is undefined
return formattedRoleName;
};
export default function RoleBasedGuard({ accessibleRoles, children }: RoleBasedGuardProp) {

View File

@@ -2,7 +2,7 @@
"greeting": "Hello",
"buttonText": "Click Me",
"infoLogin": "Enter the registered account",
"txtLogin1" : "Sign in to Hospital Portal",
"txtLogin1" : "Sign in",
"txtLogin2" : "Enter your details below",
"txtCardSearchMember1" : "Membership Query",
"txtCardSearchMember2" : "Search Member",
@@ -28,11 +28,12 @@
"txtRequestCode" : "Request Code",
"txtName" : "Name",
"txtStatus" : "Status",
"txtSearch" : "Search Name or Member ID...",
"txtSearch" : "Search...",
"txtAll" : "All",
"txtSubmissionDate" : "Admission Date",
"txtDataNotFound" : "Data Not Found",
"txtConditionDocument" : "Condition Document",
"txtBillingDocument" : "Billing Document",
"txtDiagnosisDokument" : "Diagnosis Dokument",
"txtSupportingResultDocument" : "Supporting Result Document",
"txtAddResult" : "Add Result",
@@ -77,6 +78,63 @@
"txtSecond": "Second",
"txtPleaseInput": "Please enter your new password.",
"txtNewPassword": "New Password",
"txtConfPassword": "Confirm Kata Sandi"
"txtConfPassword": "Confirm Kata Sandi",
"txtPrescriptionNumber" : "Prescription Number",
"txtPrescriptionDate" : "Date",
"txtPrescriptionPatient" : "Patient",
"txtPrescriptionPharmacy" : "Pharmacy",
"txtPrescriptionDetail" : "Detail",
"txtPrescriptionDownload" : "Download Prescription",
"txtProviderDoctorInformation" : "Provider & Doctor Information",
"txtInformasiPasien" : "Patient Information",
"txtNamaDokter" : "Doctor's Name",
"txtSpesialisasiDokter" : "Doctor's Specialization",
"txtNoPonsel" : "Mobile No.",
"txtInformasiAsuransi": "Insurance Information",
"txtNomorKartu": "Card Number",
"txtAsuransi": "Insurance",
"txtPerusahaan": "Company",
"txtTipeAsuransi": "Insurance Type",
"txtKelasAsuransi": "Insurance Class",
"txtTipeMember": "Member Type",
"txtInformasiOrder": "Order Information",
"txtNamaPenerima": "Recipient Name",
"txtAlamatPenerima": "Recipient Address",
"txtPengiriman": "Delivery",
"txtTotal": "Total",
"txtInformasiResep": "Prescription Information",
"txtNomorResep": "Prescription Number",
"txtNomorRefDokter": "Doctor's Reference Number",
"txtTanggalTerbitResep": "Prescription Issue Date",
"txtTanggalKedaluwarsa": "Expiration Date",
"txtInformasiKonsultasi": "Consultation Information",
"txtNomorPenjamin": "Guarantor Number",
"txtTanggalKonsultasi": "Consultation Date",
"txtAlergi": "Allergy",
"txtDiagnosis": "Diagnosis",
"txtObat": "Medicine",
"txtSigna": "Signa",
"txtWaktu": "Time",
"txtDurasi": "Duration",
"txtJumlah": "Quantity",
"txtCatatanObat": "Medicine Notes",
"txtDiterima": "Received",
"txtNamaPasien": "Patient Name",
"txtTanggalLahirUmur": "Date of Birth / Age",
"txtJenisKelamin": "Gender",
"txtTinggi" : "Height / Weight",
"txtLabelNew": "New",
"txtLabelAccepted": "Accepted",
"txtLabelReady": "Ready",
"txtLabelWaitingCourir": "Waiting Courir",
"txtLabelPackagePickedUp": "Package Picked Up",
"txtLabelPackageOnDelivery": "Package On Delivery",
"txtLabelPackageDelivered": "Package Delivered",
"txtLabelWaitingForPayment": "Waiting For Payment",
"txtOK": "Yes",
"txtFindingDriver": "Finding a driver...",
"txtDriverFound": "The drivers been grabbed with the ID",
"txtButtonClose": "Close",
"txtLabelFailed": "Failed"
}

View File

@@ -2,7 +2,7 @@
"greeting": "Halo",
"buttonText": "Klik Saya",
"infoLogin": "Masukan akun yang telah terdaftar",
"txtLogin1" : "Masuk ke Hospital Portal",
"txtLogin1" : "Sign in",
"txtLogin2" : "Masukkan detail Anda di bawah ini",
"txtCardSearchMember1" : "Pengajuan Jaminan",
"txtCardSearchMember2" : "Cari Anggota",
@@ -28,13 +28,14 @@
"txtRequestCode" : "Kode Pengajuan",
"txtName" : "Nama",
"txtStatus" : "Status",
"txtSearch" : "Cari Nama atau ID Anggota...",
"txtSearch" : "Cari...",
"txtAll" : "Semua",
"txtSubmissionDate" : "Tanggal Masuk",
"txtDataNotFound" : "Data Tidak Ditemukan",
"txtConditionDocument" : "Dokumen Kondisi",
"txtBillingDocument" : "Dokumen Billing",
"txtDiagnosisDokument" : "Dokumen Diagnosis",
"txtSupportingResultDocument" : "Dokumen Pendukung",
"txtSupportingResultDocument" : "Dokumen Pendukung Medis",
"txtAddResult" : "Tambah Hasil",
"txtServiceType" : "Tipe Layanan",
"txtAdditionalDocuments" : "Dokumen Tambahan",
@@ -77,5 +78,62 @@
"txtSecond": "Detik",
"txtPleaseInput": "Mohon masukan kata sandi baru Anda.",
"txtNewPassword": "Kata Sandi Baru",
"txtConfPassword": "Konfirmasi Kata Sandi"
"txtConfPassword": "Konfirmasi Kata Sandi",
"txtPrescriptionNumber" : "No Resep",
"txtPrescriptionDate" : "Tanggal",
"txtPrescriptionPatient" : "Pasien",
"txtPrescriptionPharmacy" : "Apotek",
"txtPrescriptionDetail" : "Detail",
"txtPrescriptionDownload" : "Download Resep",
"txtProviderDoctorInformation" : "Informasi Provider & Dokter",
"txtInformasiPasien" : "Informasi Pasien",
"txtNamaDokter" : "Nama Dokter",
"txtSpesialisasiDokter" : "Spesialisasi Dokter",
"txtNoPonsel" : "No Ponsel",
"txtInformasiAsuransi": "Informasi Asuransi",
"txtNomorKartu": "Nomor Kartu",
"txtAsuransi": "Asuransi",
"txtPerusahaan": "Perusahaan",
"txtTipeAsuransi": "Tipe Asuransi",
"txtKelasAsuransi": "Kelas Asuransi",
"txtTipeMember": "Tipe Member",
"txtInformasiOrder": "Informasi Order",
"txtNamaPenerima": "Nama Penerima",
"txtAlamatPenerima": "Alamat Penerima",
"txtPengiriman": "Pengiriman",
"txtTotal": "Total",
"txtInformasiResep": "Informasi Resep",
"txtNomorResep": "Nomor Resep",
"txtNomorRefDokter": "Nomor Ref Dokter",
"txtTanggalTerbitResep": "Tanggal Terbit Resep",
"txtTanggalKedaluwarsa": "Tanggal Kedaluwarsa",
"txtInformasiKonsultasi": "Informasi Konsultasi",
"txtNomorPenjamin": "Nomor Penjamin",
"txtTanggalKonsultasi": "Tanggal Konsultasi",
"txtAlergi": "Alergi",
"txtDiagnosis": "Diagnosis",
"txtObat": "Obat",
"txtSigna": "Signa",
"txtWaktu": "Waktu",
"txtDurasi": "Durasi",
"txtJumlah": "Jumlah",
"txtCatatanObat": "Catatan Obat",
"txtDiterima": "Diterima",
"txtNamaPasien": "Nama Pasien",
"txtTanggalLahirUmur": "Tanggal Lahir / Umur",
"txtJenisKelamin": "Jenis Kelamin",
"txtTinggi" : "Tinggi / Berat",
"txtLabelNew": "Baru",
"txtLabelAccepted": "Diterima Apotek",
"txtLabelReady": "Pesanan Siap Diambil",
"txtLabelWaitingCourir": "Menunggu Kurir",
"txtLabelPackagePickedUp": "Paket Sudah Diambil",
"txtLabelPackageOnDelivery": "Sedang Diantar ke Alamat Tujuan",
"txtLabelPackageDelivered": "Sudah diterima Pasien",
"txtLabelWaitingForPayment": "Menunggu Pembayaran",
"txtOK": "Ya",
"txtFindingDriver" : "Sedang mencari driver...",
"txtDriverFound" : "Driver sudah didapat dengan ID",
"txtButtonClose": "Tutup",
"txtLabelFailed": "Gagal Pengiriman"
}

View File

@@ -10,6 +10,8 @@ import useAuth from '@/hooks/useAuth';
import { getUser } from '@/utils/token';
// Join the words with a space
// ----------------------------------------------------------------------
const MENU_OPTIONS = [
@@ -34,6 +36,12 @@ export default function AccountPopover() {
const navigate = useNavigate();
const { logout } = useAuth();
const {user} = useAuth();
const formattedRoleName = user?.role.name
.split('-') // Split the string by '-'
.map(word => word.charAt(0).toUpperCase() + word.slice(1)) // Capitalize the first letter of each word
.join(' ');
const handleOpen = (event: React.MouseEvent<HTMLElement>) => {
setOpen(event.currentTarget);
};
@@ -70,7 +78,7 @@ export default function AccountPopover() {
>
<Avatar
src=""
alt="Hospital Portal"
alt="Portal"
/>
</IconButtonAnimate>
@@ -90,7 +98,7 @@ export default function AccountPopover() {
>
<Box sx={{ my: 1.5, px: 2.5 }}>
<Typography variant="subtitle2" noWrap>
Hospital Admin
{formattedRoleName}
</Typography>
<Typography variant="body2" sx={{ color: 'text.secondary' }} noWrap>
{storedUser?.email}
@@ -99,7 +107,7 @@ export default function AccountPopover() {
<Divider sx={{ borderStyle: 'dashed' }} />
<Stack sx={{ p: 1 }}>
{/* <Stack sx={{ p: 1 }}>
{MENU_OPTIONS.map((option) => (
<MenuItem
key={option.label}
@@ -111,7 +119,7 @@ export default function AccountPopover() {
{option.label}
</MenuItem>
))}
</Stack>
</Stack> */}
<Divider sx={{ borderStyle: 'dashed' }} />

View File

@@ -29,15 +29,18 @@ import axios from '@/utils/axios';
import { useSnackbar } from 'notistack';
import { LanguageContext } from '@/contexts/LanguageContext';
import useAuth from '@/hooks/useAuth';
// ----------------------------------------------------------------------
export default function NotificationsPopover() {
const { localeData }: any = useContext(LanguageContext);
const [notifications, setNotifications] = useState([]);
const {user} = useAuth();
const {enqueueSnackbar} = useSnackbar();
const getDataNotifications = async () => {
axios
.get('notifications/1')
.get('notifications/'+user?.id)
.then((response) => {
setNotifications(response.data.data.notifications);
})
@@ -47,7 +50,7 @@ export default function NotificationsPopover() {
};
useEffect(() => {
getDataNotifications();
}, []);
}, []);
const totalUnRead = notifications.filter((item) => item.isUnRead === 1).length;
@@ -137,7 +140,7 @@ export default function NotificationsPopover() {
</List>
</>
): ''}
</Scrollbar>
<Divider sx={{ borderStyle: 'dashed' }} />
@@ -256,12 +259,12 @@ function renderContent(notification: NotificationItemProps) {
title,
};
}
if (notification.type === 'mail' || notification.type === 'request_document') {
if (notification.type === 'mail' || notification.type === 'request_document' || notification.type === 'grab_status') {
return {
avatar: (
<img
alt={notification.title}
src="https://minimal-assets-api.vercel.app/assets/icons/ic_notification_mail.svg"
src="/icons/ic_mail.svg"
/>
),
title,

View File

@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
// @mui
import { styled, useTheme } from '@mui/material/styles';
@@ -15,10 +15,26 @@ import Logo from '@/components/Logo';
import Scrollbar from '@/components/Scrollbar';
import { NavSectionVertical } from '@/components/nav-section';
//
import navConfig from './NavConfig';
// import navConfig from './NavConfig';
import NavbarDocs from './NavbarDocs';
import useAuth from '@/hooks/useAuth';
import NavbarAccount from './NavbarAccount';
import CollapseButton from './CollapseButton';
import axios from '@/utils/axios';
import SvgIconStyle from '@/components/SvgIconStyle';
const getIcon = (name: string) => (
<SvgIconStyle src={`/image/${name}.svg`} sx={{ width: 1, height: 1 }} />
);
const ICONS = {
user: getIcon('ic_user'),
ecommerce: getIcon('ic_ecommerce'),
analytics: getIcon('ic_analytics'),
dashboard: getIcon('ic_dashboard'),
ic_booking: getIcon('ic_booking'),
};
// ----------------------------------------------------------------------
@@ -43,11 +59,76 @@ export default function NavbarVertical({ isOpenSidebar, onCloseSidebar }: Props)
const { pathname } = useLocation();
const {user} = useAuth();
const formattedRoleName = user?.full_name
.split('-') // Split the string by '-'
.map(word => word.charAt(0).toUpperCase() + word.slice(1)) // Capitalize the first letter of each word
.join(' '); // Join the words with a space
const isDesktop = useResponsive('up', 'lg');
const { isCollapse, collapseClick, collapseHover, onToggleCollapse, onHoverEnter, onHoverLeave } =
useCollapseDrawer();
const [navConfig, setNavConfig] = useState([]);
// console.log(navConfig);
useEffect(() => {
const fetchNavConfig = async () => {
try {
const response = await axios.get('/navigations');
const data = response.data.items;
// console.log(data);
// Pastikan user dan user.permissions terdefinisi dan merupakan array
const userPermissions = user?.permissions?.map(permission => permission.name) || [];
// Fungsi untuk memeriksa apakah pengguna memiliki izin untuk item tertentu
const hasPermission = (permission) => {
return userPermissions.includes(permission);
};
// Filter data berdasarkan izin pengguna
const filteredNavConfig = data.map(section => {
if (section.children && section.children.length > 0) {
// Cek apakah ada satu atau lebih children yang memiliki izin
const filteredChildren = section.children.filter(child => hasPermission(child.permission));
if (filteredChildren.length > 0) {
return {
...section,
children: filteredChildren
};
} else {
return null; // Lewati bagian yang tidak memiliki children dengan izin
}
}
// Jika tidak ada children, cek izin untuk section itu sendiri
// console.log(section.permission);
return hasPermission(section.permission) ? section : null;
}).filter(section => section !== null);
// console.log(filteredNavConfig);
const formattedNavConfig = filteredNavConfig.map(item => ({
items: [{
title: item.title,
path: item.path,
icon: ICONS[item.icon]
}]
}));
setNavConfig(formattedNavConfig);
} catch (error) {
console.error('Gagal mengambil konfigurasi navigasi:', error);
}
};
fetchNavConfig();
}, [user]);
console.log(navConfig);
useEffect(() => {
if (isOpenSidebar) {
onCloseSidebar();
@@ -76,10 +157,10 @@ export default function NavbarVertical({ isOpenSidebar, onCloseSidebar }: Props)
<Stack direction="row" alignItems="center" justifyContent="space-between">
<Stack direction="row" alignItems="center">
<Logo />
<Typography ml={3}>Hospital Portal</Typography>
<Typography ml={3}>{formattedRoleName}</Typography>
</Stack>
<CollapseButton onToggleCollapse={onToggleCollapse} collapseClick={collapseClick} />
</Stack>)
</Stack>)
: (
<Stack direction="row" alignItems="center" justifyContent="space-between">
<Logo />

View File

@@ -0,0 +1,119 @@
// @mui
import { Typography, Container, Grid, Card } from '@mui/material';
// hooks
import useSettings from '@/hooks/useSettings';
// components
import Page from '@/components/Page';
// theme
import CardNotification from '@/sections/dashboard/CardNotification';
import CardSearchMember from '@/sections/dashboard/CardSearchMember'
import { useContext, useEffect, useState } from 'react';
import axios from '@/utils/axios';
import { Stack } from '@mui/system';
import { Input } from '@mui/material';
//sections
import TableList from '@/sections/dashboardApotek/TableList';
import { fDate } from '@/utils/formatTime';
import DialogDetailClaim from '@/components/dialogs/DialogDetailClaim';
import HeaderBreadcrumbs from "@/components/HeaderBreadcrumbs";
// ----------------------------------------------------------------------
// const [notifications, setNotifications] = useState([])
const itemList = [
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '08:00 WIB' },
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '09:00 WIB' },
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '10:00 WIB' },
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '11:00 WIB' },
];
// ----------------------------------------------------------------------
/* ---------------------------------- types --------------------------------- */
type PolicyProps = {
myLimit: {
balance: number;
total: number;
percentage: number;
};
lockLimit: {
balance: number;
percentage: number;
};
};
/* -------------------------------------------------------------------------- */
/* ------------------------------ default data ------------------------------ */
const defaultPolicyData = {
myLimit: {
balance: 0,
total: 0,
percentage: 0,
},
lockLimit: {
balance: 0,
percentage: 0,
},
};
/* -------------------------------------------------------------------------- */
export default function Claim() {
const { themeStretch } = useSettings();
// const [tableData, setTableData] = useState([]);
const [policyData, setPolicyData] = useState<PolicyProps>(defaultPolicyData);
// TODO Remove This
//const [itemList, setItemList] = useState([]);
function handleDataLoaded(dataTable:any) {
let dummyData = [];
dataTable.map(function(data:any) {
if (data.status == 'approved') {
dummyData.push({
info: `LOG Approved for member ${data.member.full_name}`,
date: fDate(data.created_at, "dd MMMM"),
time: fDate(data.created_at, "HH:mm")
})
}
})
//setItemList(dummyData);
}
return (
<Page title="Dashboard">
<Container maxWidth={themeStretch ? false : 'xl'}>
<Grid container spacing={2}>
{/* <Grid item xs={12} lg={12} md={12}>
<CardSearchMember/>
</Grid> */}
{/*<Grid item xs={12} lg={6} md={6}>
<CardNotification data={itemList} />
</Grid>*/}
<Grid item xs={12} lg={12} md={12}>
{/* <HeaderBreadcrumbs
heading={'Dashboard'}
links={[
{
name: 'Dashboard',
href: '/dashboard-apotek',
},
{
name: 'Dashboard',
href: '/list',
},
]}
/> */}
<Card>
<TableList/>
</Card>
</Grid>
</Grid>
</Container>
</Page>
);
}

View File

@@ -11,12 +11,16 @@ import Register from '@/pages/auth/Register';
import VerifyCode from '@/pages/auth/VerifyCode';
import { AuthProvider } from '@/contexts/LaravelAuthContext';
import AuthGuard from '@/guards/AuthGuard';
import useAuth from '@/hooks/useAuth';
import RoleBasedGuard from '@/guards/RoleBasedGuard';
// ----------------------------------------------------------------------
const Loadable = (Component: ElementType) => (props: any) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { pathname } = useLocation();
const {user} = useAuth();
const formattedRoleName = user?.role.name;
return (
<Suspense fallback={<LoadingScreen isDashboard={pathname.includes('/dashboard')} />}>
@@ -50,11 +54,35 @@ export default function Router() {
</AuthProvider>
),
},
{
path: 'reset-password',
element: (
<AuthProvider>
<ResetPassword />
</AuthProvider>
),
},
{
path: 'forget-password',
element: (
<AuthProvider>
<ForgetPassword />
</AuthProvider>
),
},
{
path: 'verify',
element: (
<AuthProvider>
<VerifyCode />
</AuthProvider>
),
},
// { path: 'login-unprotected', element: <Login /> },
// { path: 'register-unprotected', element: <Register /> },
{ path: 'reset-password', element: <ResetPassword /> },
{ path: 'forget-password', element: <ForgetPassword /> },
{ path: 'verify', element: <VerifyCode /> },
// { path: 'reset-password', element: <ResetPassword /> },
// { path: 'forget-password', element: <ForgetPassword /> },
// { path: 'verify', element: <VerifyCode /> },
],
},
// {
@@ -74,11 +102,19 @@ export default function Router() {
{ element: <Navigate to="/dashboard" replace />, index: true },
{
path: 'dashboard',
element: <Dashboard />,
element: (
<RoleBasedGuard accessibleRoles={['hospital-admin']}>
<Dashboard />
</RoleBasedGuard>
),
},
{
path: '/detail/:id',
element: <DetailClaimReport />,
element: (
<RoleBasedGuard accessibleRoles={['hospital-admin']}>
<DetailClaimReport />
</RoleBasedGuard>
),
},
],
},
@@ -95,18 +131,54 @@ export default function Router() {
{ element: <Navigate to="/claim" replace />, index: true },
{
path: 'claim',
element: <Claim />,
element: (
<RoleBasedGuard accessibleRoles={['hospital-admin']}>
<Claim />
</RoleBasedGuard>
),
},
{
path: '/claim/detail/:id',
element: <DetailClaim />,
element: (
<RoleBasedGuard accessibleRoles={['hospital-admin']}>
<DetailClaim />
</RoleBasedGuard>
),
},
],
},
{
path: '/',
element: (
<AuthProvider>
<AuthGuard>
<DashboardLayout />
</AuthGuard>
</AuthProvider>
),
children: [
{ element: <Navigate to="/prescription-orders" replace />, index: true },
{
path: 'prescription-orders',
element: (
<RoleBasedGuard accessibleRoles={['admin-apotek', 'cs-lms']}>
<DashboardApotek />
</RoleBasedGuard>
),
},
],
},
{
path: '*',
element: <LogoOnlyLayout />,
element: (
<AuthProvider>
<AuthGuard>
<LogoOnlyLayout />
</AuthGuard>
</AuthProvider>
),
children: [
{ path: '404', element: <NotFound /> },
{ path: '*', element: <Navigate to="/404" replace /> },
@@ -123,6 +195,7 @@ const ForgetPassword = Loadable(lazy(() => import('@/pages/auth/ForgetPassword')
// Dashboard
const Dashboard = Loadable(lazy(() => import('@/pages/Dashboard')));
const Claim = Loadable(lazy(() => import('@/pages/Claim')));
const DashboardApotek = Loadable(lazy(() => import('@/pages/DashboardApotek')));
const NotFound = Loadable(lazy(() => import('@/pages/Page404')));
const DetailClaimReport = Loadable(lazy(()=> import('@/sections/dashboard/Detail')));

View File

@@ -148,7 +148,7 @@ export default function DialogFinalLog({ member, getData, onClose, handleSubmitS
{/* -------------------------------Upload Dokumen Kondisi------------------------------- */}
<Stack sx={{ marginTop: 2 }}>
<Typography variant="body1" sx={{fontWeight:'bold'}}>
{localeData.txtConditionDocument}
{localeData.txtBillingDocument}
</Typography>
{/* <Typography variant="body2">Hasil Lab, </Typography> */}
<Stack

View File

@@ -0,0 +1,440 @@
/* ---------------------------------- @mui ---------------------------------- */
import { Stack, Button, MenuItem, SelectChangeEvent, Tab, Tabs, Card, Box } from '@mui/material';
/* ---------------------------------- axios --------------------------------- */
// import axios from 'axios';
import axios from '../../utils/axios';
import { styled } from '@mui/material/styles';
/* ---------------------------------- react --------------------------------- */
import { useContext, useEffect, useState } from 'react';
/* -------------------------------- component ------------------------------- */
import Iconify from '../../components/Iconify';
import TableComponent from '../../components/Table';
/* ---------------------------------- theme --------------------------------- */
import palette from '../../theme/palette';
//import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate';
import { HeadCell, Order, PaginationTableProps } from '../../@types/table';
import { useSearchParams, useNavigate } from 'react-router-dom';
import { fDate, fDateSuffix, fDateTime } from '../../utils/formatTime';
import Typography from '@mui/material/Typography';
import { format } from 'date-fns';
import TableMoreMenu from '../../components/table/TableMoreMenu';
import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
import HistoryIcon from '@mui/icons-material/History';
import SearchIcon from '@mui/icons-material/Search';
import Label from '../../components/Label';
import { enqueueSnackbar } from 'notistack';
import { LoadingButton, TabPanel } from "@mui/lab";
import { LanguageContext } from '@/contexts/LanguageContext';
import MuiDialog from '@/components/MuiDialog';
import DialogMember from '@/sections/dashboard/DialogMember';
import DialogClaimSubmit from '@/sections/dashboard/DialogClaimSubmit';
import { fPostFormat } from '@/utils/formatTime';
export default function TableList() {
const navigate = useNavigate();
const { localeData }: any = useContext(LanguageContext);
const [data, setData] = useState([]);
// Download Resep
async function handleDownloadPrescription(link_download:any) {
window.open(link_download, '_blank');
}
/* -------------------------------------------------------------------------- */
/* setting up for the table */
/* -------------------------------------------------------------------------- */
const [isLoading, setIsLoading] = useState(true);
const loadings = {
isLoading: isLoading,
setIsLoading: setIsLoading,
};
/* ------------------------------ handle params ----------------------------- */
const [searchParams, setSearchParams] = useSearchParams();
const [appliedParams, setAppliedParams] = useState({});
const params = {
searchParams: searchParams,
setSearchParams: setSearchParams,
appliedParams: appliedParams,
setAppliedParams: setAppliedParams,
};
/* -------------------------------------------------------------------------- */
/* ------------------------------ handle order ------------------------------ */
const [order, setOrder] = useState<Order>('desc');
const [orderBy, setOrderBy] = useState('dTanggalresep');
const orders = {
order: order,
setOrder: setOrder,
orderBy: orderBy,
setOrderBy: setOrderBy,
};
/* -------------------------------------------------------------------------- */
/* ---------------------------- handle pagination --------------------------- */
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
const [paginationTable, setPaginationTable] = useState<PaginationTableProps>({
current_page: 0,
from: 0,
last_page: 0,
links: [],
path: '',
per_page: 0,
to: 0,
total: 0,
});
const paginations = {
page: page,
setPage: setPage,
rowsPerPage: rowsPerPage,
setRowsPerPage: setRowsPerPage,
paginationTable: paginationTable,
setPaginationTable: setPaginationTable,
};
/* -------------------------------------------------------------------------- */
// ----------------------------------------- handle selected ---------------------
const [selectAll, setSelectAll] = useState(false);
const [selectedRows, setSelectedRows] = useState([]);
const [dataTableData, setDataTableData] = useState<any>();
const handleSelectAll = () => {
setSelectAll(!selectAll);
if (!selectAll) {
const requestedIds = dataTableData?.data
.filter((row: { status: string, check_claim:any }) => row.status === 'approved' && !row.check_claim)
.map((row: { id: any }) => row.id);
setSelectedRows(requestedIds);
} else {
setSelectedRows([]);
}
};
const handleCheckboxChange = (id: any) => {
setSelectedRows(prevSelectedRows => {
const isSelected = prevSelectedRows.includes(id);
if (isSelected) {
return prevSelectedRows.filter(rowId => rowId !== id);
} else {
return [...prevSelectedRows, id];
}
});
};
const [openDialogSubmit, setOpenDialogSubmit] = useState(false);
const handleCloseDialogSubmit = () => {
setOpenDialogSubmit(false);
}
const [valDialog, setValDialog] = useState('');
const [reasonDecline, setReasonDecline] = useState('');
const handleReasonDeclineChange = (event: { target: { value: SetStateAction<string>; }; }) => {
setReasonDecline(event.target.value);
};
const selected = {
useSelected: false,
selectAll: selectAll,
handleSelectAll: handleSelectAll,
selectedRows: selectedRows,
handleCheckboxChange : handleCheckboxChange,
totRows: 9,
useDecline: false,
txtDecline: 'Decline',
useApprove:true,
txtApprove: 'Submit Claim',
setOpenDialogSubmit: setOpenDialogSubmit,
setValDialog: setValDialog
};
/* ------------------------------ handle search ----------------------------- */
const [searchText, setSearchText] = useState('');
const handleSearchSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (searchText === '') {
searchParams.delete('search');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([...searchParams.entries(), ['search', searchText]]);
setAppliedParams(params);
}
};
const searchs = {
useSearchs: true,
searchText: searchText,
setSearchText: setSearchText,
handleSearchSubmit: handleSearchSubmit,
};
/* ------------------------------ handle filter ----------------------------- */
const [statusValue, setStatusValue] = useState('all');
const [filterData, setStatusData] = useState([]);
// handle status
const handleStatusChanges = (event: SelectChangeEvent) => {
setStatusValue(event.target.value as string);
if (event.target.value === 'all') {
searchParams.delete('status');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([
...searchParams.entries(),
['status', event.target.value as string],
]);
setAppliedParams(params);
}
};
const filterStatus = {
useFilter: true,
config: {
label: 'Status',
statusValue: statusValue,
filterData: filterData,
handleStatusChange: handleStatusChanges,
},
};
// handle start date
const [startDateValue, setStartDateValue] = useState('');
const handleStartDateChanges = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const newStartDateValue = event.currentTarget.elements['date-input'].value;
setStartDateValue(newStartDateValue);
if (newStartDateValue === '') {
searchParams.delete('start_date');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([...searchParams.entries(), ['start_date', newStartDateValue]]);
setAppliedParams(params);
}
};
const filterStartDate = {
useFilter: true,
startDate: startDateValue,
setStartDate: setStartDateValue,
handleStartDateChange: handleStartDateChanges,
};
// handle end date
const [endDateValue, setEndDateValue] = useState('');
const handleEndDateChanges = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const newEndDateValue = event.currentTarget.elements['date-input'].value;
setEndDateValue(newEndDateValue);
if (newEndDateValue === '') {
searchParams.delete('end_date');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([...searchParams.entries(), ['end_date', newEndDateValue]]);
setAppliedParams(params);
}
};
const filterEndDate = {
useFilter: true,
endDate: endDateValue,
setEndDate: setEndDateValue,
handleEndDateChange: handleEndDateChanges,
};
/* -------------------------------- headCell Claim -------------------------------- */
const headCells: HeadCell<never>[] = [
{
id: 'no_resep',
align: 'left',
label: localeData.txtPrescriptionNumber,
isSort: true,
},
{
id: 'tanggal',
align: 'left',
label: localeData.txtPrescriptionDate,
isSort: true,
},
{
id: 'pasien',
align: 'center',
label: localeData.txtPrescriptionPatient,
isSort: true,
},
{
id: 'apotek',
align: 'center',
label: localeData.txtPrescriptionPharmacy,
isSort: true,
},
{
id: 'status',
align: 'center',
label: localeData.txtStatus,
isSort: true,
},
{
id: 'action',
align: 'right',
label: '',
isSort: false,
},
];
useEffect(() => {
getData();
}, [appliedParams, searchParams, order, orderBy, setSearchParams]);
const [openRowId, setOpenRowId] = useState<number | null>(null);
function getData()
{
(async () => {
setIsLoading(true);
await new Promise((resolve) => setTimeout(resolve, 250));
const parameters =
Object.keys(appliedParams).length !== 0
? appliedParams
: Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]);
const response = await axios.get(`/get-prescription-orders`, {
params: { ...parameters, type: 'prescription-orders' },
});
setDataTableData(response.data);
setData(
response.data.data.map((obj: any) => ({
...obj,
status:
obj.status === 'waiting_pharmacy' ? (
<Label color='default'>
{localeData.txtLabelNew}
</Label>
) : obj.status === 'order_prepared' ? (
<Label color='primary' >
{localeData.txtLabelAccepted}
</Label>
) : obj.status === 'ready' ? (
<Label color='primary'>
{localeData.txtLabelReady}
</Label>
) : obj.status === 'waiting_for_courir' ? (
<Label color='primary'>
{localeData.txtLabelWaitingCourir}
</Label>
) : obj.status === 'package_picked_up' ? (
<Label color='primary'>
{localeData.txtLabelPackagePickedUp}
</Label>
) : obj.status === 'package_on_delivery' ? (
<Label color='primary'>
{localeData.txtLabelPackageOnDelivery}
</Label>
) : obj.status === 'package_delivered' ? (
<Label color='primary'>
{localeData.txtLabelPackageDelivered}
</Label>
) : obj.status === 'waiting_for_payment' ? (
<Label color='primary'>
{localeData.txtLabelWaitingForPayment}
</Label>
): obj.status === 'failed' ? (
<Label color='error'>
{localeData.txtLabelFailed}
</Label>
) : (
<Label color='primary'>
Pending
</Label>
),
tanggal:
<Label>
{obj.tanggal ? fDateTime(obj.tanggal) : ''}
</Label>
,
valid_tanggal:
<Label>
{obj.valid_tanggal ? fDateTime(obj.valid_tanggal) : ''}
</Label>
,
action:
<TableMoreMenu actions={
<>
<MenuItem onClick={() => setOpenRowId(obj.id === openRowId ? null : obj.id)}>
<Iconify icon="eva:eye-fill" />
{localeData.txtPrescriptionDetail}
</MenuItem>
<MenuItem onClick={() => handleDownloadPrescription(obj.link_download)}>
<Iconify icon="eva:download-fill" />
{localeData.txtPrescriptionDownload}
</MenuItem>
</>
} />
}))
);
setPaginationTable(response.data);
setRowsPerPage(response.data.per_page);
if (searchParams.get('page')) {
//@ts-ignore
const currentPage = parseInt(searchParams.get('page')) - 1;
paginationTable.current_page = currentPage;
setPage(currentPage);
}
const status:any = [
{"id": "waiting_for_payment", "name": localeData.txtLabelWaitingForPayment },
{"id": "waiting_pharmacy", "name": localeData.txtLabelNew },
{"id": "order_prepared", "name": localeData.txtLabelAccepted },
{"id": "ready", "name": localeData.txtLabelReady },
{"id": "waiting_for_courir", "name": localeData.txtLabelWaitingCourir },
{"id": "package_picked_up", "name": localeData.txtLabelPackagePickedUp },
{"id": "package_on_delivery", "name": localeData.txtLabelPackageOnDelivery },
{"id": "package_delivered", "name": localeData.txtLabelPackageDelivered },
{"id": "failed", "name": localeData.txtLabelFailed },
];
setStatusData(status)
setIsLoading(false);
})();
}
return (
<>
<TableComponent
headCells={headCells}
rows={data}
orders={orders}
paginations={paginations}
loadings={loadings}
params={params}
searchs={searchs}
filterStatus={filterStatus}
selected={selected}
// filterStartDate={filterStartDate}
// filterEndDate={filterEndDate}
openRowId={openRowId} // Pass the currently opened row ID
setOpenRowId={setOpenRowId} // Pass the function to set the opened row ID
reloadData={getData}
/>
</>
);
}

View File

@@ -11,6 +11,40 @@ export function fDateTime(date: Date | string | number) {
return format(new Date(date), 'dd MMM yyyy HH:mm');
}
// Function to calculate the age from the birthdate
function calculateAge(birthDate: Date): number {
const today = new Date();
const age = today.getFullYear() - birthDate.getFullYear();
const monthDifference = today.getMonth() - birthDate.getMonth();
const dayDifference = today.getDate() - birthDate.getDate();
// Adjust age if birthday hasn't occurred yet this year
if (monthDifference < 0 || (monthDifference === 0 && dayDifference < 0)) {
return age - 1;
}
return age;
}
// Extended function to format the date and include the age if it's a birthdate
export function fDateTimeWithAge(date: Date | string | number): string {
const birthDate = new Date(date);
const formattedDate = format(birthDate, 'dd MMM yyyy');
const age = calculateAge(birthDate);
// If the age is 0, the output should be months instead of years
let ageText = age > 0 ? `${age} years old` : '';
if (age === 0) {
const monthsOld = new Date().getMonth() - birthDate.getMonth() +
(12 * (new Date().getFullYear() - birthDate.getFullYear()));
ageText = `${monthsOld} months old`;
}
return `${formattedDate} / ${ageText}`;
}
export function fTimestamp(date: Date | string | number) {
return getTime(new Date(date));
}

View File

@@ -1 +0,0 @@
import{r,i as a,a as t}from"./jsx-runtime_commonjs-proxy.b87625c0.js";var e={},o=a.exports;Object.defineProperty(e,"__esModule",{value:!0});var u=e.default=void 0,i=o(r()),d=t,l=(0,i.default)((0,d.jsx)("path",{d:"M11.67 3.87 9.9 2.1 0 12l9.9 9.9 1.77-1.77L3.54 12z"}),"ArrowBackIos");u=e.default=l;export{u as d};

View File

@@ -1 +0,0 @@
import{a as d,g as u,s as C,P as p,r as f,u as m,e as x,_ as n,j as h,h as y,i as g}from"./index.b0a49137.js";function v(s){return d("MuiCard",s)}u("MuiCard",["root"]);const w=["className","raised"],M=s=>{const{classes:e}=s;return g({root:["root"]},v,e)},P=C(p,{name:"MuiCard",slot:"Root",overridesResolver:(s,e)=>e.root})(()=>({overflow:"hidden"})),R=f.exports.forwardRef(function(e,t){const o=m({props:e,name:"MuiCard"}),{className:i,raised:r=!1}=o,l=x(o,w),a=n({},o,{raised:r}),c=M(a);return h(P,n({className:y(c.root,i),elevation:r?8:void 0,ref:t,ownerState:a},l))}),_=R;export{_ as C};

View File

@@ -1 +0,0 @@
import{c as h,j as t,g as P,a as B,s as g,aQ as S,b as v,_ as n,a6 as M,r as d,u as _,e as H,h as R,i as O}from"./index.b0a49137.js";import{S as U}from"./SwitchBase.6ffeba1b.js";const V=h(t("path",{d:"M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"}),"CheckBoxOutlineBlank"),j=h(t("path",{d:"M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"}),"CheckBox"),L=h(t("path",{d:"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 10H7v-2h10v2z"}),"IndeterminateCheckBox");function N(o){return B("MuiCheckbox",o)}const w=P("MuiCheckbox",["root","checked","disabled","indeterminate","colorPrimary","colorSecondary"]),p=w,E=["checkedIcon","color","icon","indeterminate","indeterminateIcon","inputProps","size","className"],F=o=>{const{classes:e,indeterminate:c,color:s}=o,r={root:["root",c&&"indeterminate",`color${v(s)}`]},a=O(r,N,e);return n({},e,a)},Q=g(U,{shouldForwardProp:o=>S(o)||o==="classes",name:"MuiCheckbox",slot:"Root",overridesResolver:(o,e)=>{const{ownerState:c}=o;return[e.root,c.indeterminate&&e.indeterminate,c.color!=="default"&&e[`color${v(c.color)}`]]}})(({theme:o,ownerState:e})=>n({color:(o.vars||o).palette.text.secondary},!e.disableRipple&&{"&:hover":{backgroundColor:o.vars?`rgba(${e.color==="default"?o.vars.palette.action.activeChannel:o.vars.palette.primary.mainChannel} / ${o.vars.palette.action.hoverOpacity})`:M(e.color==="default"?o.palette.action.active:o.palette[e.color].main,o.palette.action.hoverOpacity),"@media (hover: none)":{backgroundColor:"transparent"}}},e.color!=="default"&&{[`&.${p.checked}, &.${p.indeterminate}`]:{color:(o.vars||o).palette[e.color].main},[`&.${p.disabled}`]:{color:(o.vars||o).palette.action.disabled}})),T=t(j,{}),W=t(V,{}),q=t(L,{}),A=d.exports.forwardRef(function(e,c){var s,r;const a=_({props:e,name:"MuiCheckbox"}),{checkedIcon:b=T,color:f="primary",icon:I=W,indeterminate:i=!1,indeterminateIcon:u=q,inputProps:z,size:l="medium",className:$}=a,y=H(a,E),m=i?u:I,C=i?u:b,k=n({},a,{color:f,indeterminate:i,size:l}),x=F(k);return t(Q,n({type:"checkbox",inputProps:n({"data-indeterminate":i},z),icon:d.exports.cloneElement(m,{fontSize:(s=m.props.fontSize)!=null?s:l}),checkedIcon:d.exports.cloneElement(C,{fontSize:(r=C.props.fontSize)!=null?r:l}),ownerState:k,ref:c,className:R(x.root,$)},y,{classes:x}))}),J=A;export{J as C};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{au as x,n as g,r as l,Z as b,a0 as v,f as i,F as y,S as n,T as a,j as e,B as w,D as s,q as D}from"./index.b0a49137.js";import{c as d,b as C}from"./formatTime.0646b9d0.js";import{S,a as j,b as I}from"./Stepper.49691c4e.js";import{C as p}from"./Card.a4168b31.js";import"./index.49ea62c1.js";const Y=["Review","Approval","Disbursement"],U=()=>{const{id:h}=x(),m=g(),{corporateValue:c}=l.exports.useContext(b),[f,k]=l.exports.useState(c),[t,u]=l.exports.useState(null);return l.exports.useEffect(()=>{v.get(`${c}/claim-report/${h}`).then(r=>{u(r.data.data)}).catch(r=>{console.error("Terjadi kesalahan:",r)})},[]),l.exports.useEffect(()=>{f!==c&&m("/claim-report")},[c]),i(y,{children:[i(n,{alignItems:"center",justifyContent:"space-between",direction:"row",sx:{marginTop:1},children:[i(a,{variant:"subtitle1",sx:{height:"max-content"},children:["Claim Request for ",t==null?void 0:t.fullName]}),i(n,{children:[e(a,{variant:"caption",children:"Submission date"}),e(a,{variant:"caption",children:d(t?t.submissionDate:new Date,"dd / MM / yyyy")})]})]}),e(w,{sx:{width:"100%",marginTop:2},children:e(S,{activeStep:(t==null?void 0:t.status)==="approved"?1:(t==null?void 0:t.status)==="requested"?0:2,alternativeLabel:!0,children:Y.map(r=>e(j,{children:e(I,{children:r})},r))})}),e(n,{marginTop:2,children:e(a,{variant:"subtitle1",paddingY:2,children:C(t?t==null?void 0:t.histories[0].created_at:new Date)})}),i(n,{direction:"row",spacing:2,children:[e(s,{orientation:"vertical",flexItem:!0,sx:{borderStyle:"dashed"}}),i(n,{spacing:2,sx:{flex:1,maxWidth:"100%"},children:[t==null?void 0:t.histories.map((r,o)=>i(p,{sx:{paddingY:2,paddingX:3},children:[e(n,{direction:"row",justifyContent:"space-between",alignItems:"center",children:i(a,{variant:"body1",children:[d(r.created_at,"HH:mm")," WIB"]})}),e(s,{sx:{marginY:2}}),i(n,{children:[i(a,{variant:"subtitle2",color:"#404040",children:["Details : ",r.description]}),e(a,{variant:"caption",color:"#757575",sx:{marginTop:2,marginBottom:1},children:r.title})]})]},`${r.title}-${o}`)),i(p,{sx:{paddingY:2,paddingX:3},children:[e(n,{direction:"row",justifyContent:"space-between",alignItems:"center",children:i(a,{variant:"body1",fontWeight:600,children:[e(D,{icon:"eva:file-text-fill"})," Dokumen Kelengkapan"]})}),e(s,{sx:{marginY:2}}),e(a,{fontWeight:"600",children:"Kondisi"}),i(n,{children:[e(n,{divider:e(s,{orientation:"horizontal",flexItem:!0}),spacing:1,sx:{marginY:2},children:t&&t.files.claimConditions.map((r,o)=>e(n,{direction:"row",justifyContent:"space-between",children:e("a",{href:r.fileUrl,target:"_blank",style:{textDecoration:"none"},rel:"noreferrer",children:i(a,{sx:{color:"text.secondary"},variant:"subtitle2",children:["- ",r.fileName]})})},o))}),e(a,{fontWeight:"600",children:"Diagnosa"}),e(n,{divider:e(s,{orientation:"horizontal",flexItem:!0}),spacing:1,sx:{marginY:2},children:t&&t.files.claimDiagnosis.map((r,o)=>e(n,{direction:"row",justifyContent:"space-between",children:e("a",{href:r.fileUrl,target:"_blank",style:{textDecoration:"none"},rel:"noreferrer",children:i(a,{sx:{color:"text.secondary"},variant:"subtitle2",children:["- ",r.fileName]})})},o))}),e(a,{fontWeight:"600",children:"Hasil"}),e(n,{divider:e(s,{orientation:"horizontal",flexItem:!0}),spacing:1,sx:{marginY:2},children:t&&t.files.claimResults.map((r,o)=>e(n,{direction:"row",justifyContent:"space-between",children:e("a",{href:r.fileUrl,target:"_blank",style:{textDecoration:"none"},rel:"noreferrer",children:i(a,{sx:{color:"text.secondary"},variant:"subtitle2",children:["- ",r.fileName]})})},o))})]})]})]})]})]})};export{U as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{g as A,a as C,s as I,_ as c,r as b,u as E,e as L,H as $,j as r,J as z,h as T,T as R,f as _,b as m,i as j}from"./index.b0a49137.js";function F(e){return C("MuiInputAdornment",e)}const M=A("MuiInputAdornment",["root","filled","standard","outlined","positionStart","positionEnd","disablePointerEvents","hiddenLabel","sizeSmall"]),f=M;var g;const N=["children","className","component","disablePointerEvents","disableTypography","position","variant"],S=(e,t)=>{const{ownerState:n}=e;return[t.root,t[`position${m(n.position)}`],n.disablePointerEvents===!0&&t.disablePointerEvents,t[n.variant]]},U=e=>{const{classes:t,disablePointerEvents:n,hiddenLabel:o,position:s,size:a,variant:l}=e,d={root:["root",n&&"disablePointerEvents",s&&`position${m(s)}`,l,o&&"hiddenLabel",a&&`size${m(a)}`]};return j(d,F,t)},w=I("div",{name:"MuiInputAdornment",slot:"Root",overridesResolver:S})(({theme:e,ownerState:t})=>c({display:"flex",height:"0.01em",maxHeight:"2em",alignItems:"center",whiteSpace:"nowrap",color:(e.vars||e).palette.action.active},t.variant==="filled"&&{[`&.${f.positionStart}&:not(.${f.hiddenLabel})`]:{marginTop:16}},t.position==="start"&&{marginRight:8},t.position==="end"&&{marginLeft:8},t.disablePointerEvents===!0&&{pointerEvents:"none"})),H=b.exports.forwardRef(function(t,n){const o=E({props:t,name:"MuiInputAdornment"}),{children:s,className:a,component:l="div",disablePointerEvents:d=!1,disableTypography:x=!1,position:u,variant:v}=o,P=L(o,N),i=$()||{};let p=v;v&&i.variant,i&&!p&&(p=i.variant);const h=c({},o,{hiddenLabel:i.hiddenLabel,size:i.size,disablePointerEvents:d,position:u,variant:p}),y=U(h);return r(z.Provider,{value:null,children:r(w,c({as:l,ownerState:h,className:T(y.root,a),ref:n},P,{children:typeof s=="string"&&!x?r(R,{color:"text.secondary",children:s}):_(b.exports.Fragment,{children:[u==="start"?g||(g=r("span",{className:"notranslate",children:"\u200B"})):null,s]})}))})}),J=H;export{J as I};

View File

@@ -1 +0,0 @@
import{c as r,j as o}from"./index.b0a49137.js";const t=r(o("path",{d:"M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"}),"KeyboardArrowLeft"),e=r(o("path",{d:"M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"}),"KeyboardArrowRight");export{e as K,t as a};

View File

@@ -1 +0,0 @@
import{v as p,j as d,s as g,a6 as c}from"./index.b0a49137.js";const y=g("span")(({theme:t,ownerState:r})=>{const n=t.palette.mode==="light",{color:l,variant:a}=r,e=o=>({color:t.palette[o].contrastText,backgroundColor:t.palette[o].main}),i=o=>({color:t.palette[o].main,backgroundColor:"transparent",border:`1px solid ${t.palette[o].main}`}),s=o=>({color:t.palette[o][n?"dark":"light"],backgroundColor:c(t.palette[o].main,.16)});return{height:22,minWidth:22,lineHeight:0,borderRadius:6,alignItems:"center",whiteSpace:"nowrap",display:"inline-flex",justifyContent:"center",padding:t.spacing(0,1),color:t.palette.grey[800],fontSize:t.typography.pxToRem(12),fontFamily:t.typography.fontFamily,backgroundColor:t.palette.grey[300],fontWeight:t.typography.fontWeightBold,...l!=="default"?{...a==="filled"&&{...e(l)},...a==="outlined"&&{...i(l)},...a==="ghost"&&{...s(l)}}:{...a==="outlined"&&{backgroundColor:"transparent",color:t.palette.text.primary,border:`1px solid ${t.palette.grey[50032]}`},...a==="ghost"&&{color:n?t.palette.text.secondary:t.palette.common.white,backgroundColor:t.palette.grey[50016]}}}});function f({color:t="default",variant:r="ghost",children:n,sx:l}){const a=p();return d(y,{ownerState:{color:t,variant:r},sx:l,theme:a,children:n})}export{f as L};

View File

@@ -1 +0,0 @@
import{c as a,j as s}from"./index.b0a49137.js";const o=a(s("path",{d:"M18.41 16.59L13.82 12l4.59-4.59L17 6l-6 6 6 6zM6 6h2v12H6z"}),"FirstPage"),c=a(s("path",{d:"M5.59 7.41L10.18 12l-4.59 4.59L7 18l6-6-6-6zM16 6h2v12h-2z"}),"LastPage");export{o as F,c as L};

View File

@@ -1,54 +0,0 @@
import{g as q,a as M,C as h,s as b,b as t,_ as s,E as C,r as z,u as D,e as T,v as j,f as U,j as p,h as O,i as A,l as K,d as w}from"./index.b0a49137.js";function X(r){return M("MuiLinearProgress",r)}const E=q("MuiLinearProgress",["root","colorPrimary","colorSecondary","determinate","indeterminate","buffer","query","dashed","dashedColorPrimary","dashedColorSecondary","bar","barColorPrimary","barColorSecondary","bar1Indeterminate","bar1Determinate","bar1Buffer","bar2Indeterminate","bar2Buffer"]),er=E,S=["className","color","value","valueBuffer","variant"];let l=r=>r,x,L,k,B,I,_;const v=4,W=h(x||(x=l`
0% {
left: -35%;
right: 100%;
}
60% {
left: 100%;
right: -90%;
}
100% {
left: 100%;
right: -90%;
}
`)),F=h(L||(L=l`
0% {
left: -200%;
right: 100%;
}
60% {
left: 107%;
right: -8%;
}
100% {
left: 107%;
right: -8%;
}
`)),G=h(k||(k=l`
0% {
opacity: 1;
background-position: 0 -23px;
}
60% {
opacity: 0;
background-position: 0 -23px;
}
100% {
opacity: 1;
background-position: -200px -23px;
}
`)),H=r=>{const{classes:e,variant:a,color:o}=r,m={root:["root",`color${t(o)}`,a],dashed:["dashed",`dashedColor${t(o)}`],bar1:["bar",`barColor${t(o)}`,(a==="indeterminate"||a==="query")&&"bar1Indeterminate",a==="determinate"&&"bar1Determinate",a==="buffer"&&"bar1Buffer"],bar2:["bar",a!=="buffer"&&`barColor${t(o)}`,a==="buffer"&&`color${t(o)}`,(a==="indeterminate"||a==="query")&&"bar2Indeterminate",a==="buffer"&&"bar2Buffer"]};return A(m,X,e)},P=(r,e)=>e==="inherit"?"currentColor":r.vars?r.vars.palette.LinearProgress[`${e}Bg`]:r.palette.mode==="light"?K(r.palette[e].main,.62):w(r.palette[e].main,.5),J=b("span",{name:"MuiLinearProgress",slot:"Root",overridesResolver:(r,e)=>{const{ownerState:a}=r;return[e.root,e[`color${t(a.color)}`],e[a.variant]]}})(({ownerState:r,theme:e})=>s({position:"relative",overflow:"hidden",display:"block",height:4,zIndex:0,"@media print":{colorAdjust:"exact"},backgroundColor:P(e,r.color)},r.color==="inherit"&&r.variant!=="buffer"&&{backgroundColor:"none","&::before":{content:'""',position:"absolute",left:0,top:0,right:0,bottom:0,backgroundColor:"currentColor",opacity:.3}},r.variant==="buffer"&&{backgroundColor:"transparent"},r.variant==="query"&&{transform:"rotate(180deg)"})),Q=b("span",{name:"MuiLinearProgress",slot:"Dashed",overridesResolver:(r,e)=>{const{ownerState:a}=r;return[e.dashed,e[`dashedColor${t(a.color)}`]]}})(({ownerState:r,theme:e})=>{const a=P(e,r.color);return s({position:"absolute",marginTop:0,height:"100%",width:"100%"},r.color==="inherit"&&{opacity:.3},{backgroundImage:`radial-gradient(${a} 0%, ${a} 16%, transparent 42%)`,backgroundSize:"10px 10px",backgroundPosition:"0 -23px"})},C(B||(B=l`
animation: ${0} 3s infinite linear;
`),G)),V=b("span",{name:"MuiLinearProgress",slot:"Bar1",overridesResolver:(r,e)=>{const{ownerState:a}=r;return[e.bar,e[`barColor${t(a.color)}`],(a.variant==="indeterminate"||a.variant==="query")&&e.bar1Indeterminate,a.variant==="determinate"&&e.bar1Determinate,a.variant==="buffer"&&e.bar1Buffer]}})(({ownerState:r,theme:e})=>s({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",backgroundColor:r.color==="inherit"?"currentColor":(e.vars||e).palette[r.color].main},r.variant==="determinate"&&{transition:`transform .${v}s linear`},r.variant==="buffer"&&{zIndex:1,transition:`transform .${v}s linear`}),({ownerState:r})=>(r.variant==="indeterminate"||r.variant==="query")&&C(I||(I=l`
width: auto;
animation: ${0} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
`),W)),Y=b("span",{name:"MuiLinearProgress",slot:"Bar2",overridesResolver:(r,e)=>{const{ownerState:a}=r;return[e.bar,e[`barColor${t(a.color)}`],(a.variant==="indeterminate"||a.variant==="query")&&e.bar2Indeterminate,a.variant==="buffer"&&e.bar2Buffer]}})(({ownerState:r,theme:e})=>s({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left"},r.variant!=="buffer"&&{backgroundColor:r.color==="inherit"?"currentColor":(e.vars||e).palette[r.color].main},r.color==="inherit"&&{opacity:.3},r.variant==="buffer"&&{backgroundColor:P(e,r.color),transition:`transform .${v}s linear`}),({ownerState:r})=>(r.variant==="indeterminate"||r.variant==="query")&&C(_||(_=l`
width: auto;
animation: ${0} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite;
`),F)),Z=z.exports.forwardRef(function(e,a){const o=D({props:e,name:"MuiLinearProgress"}),{className:m,color:N="primary",value:g,valueBuffer:y,variant:i="indeterminate"}=o,R=T(o,S),c=s({},o,{color:N,variant:i}),f=H(c),$=j(),u={},d={bar1:{},bar2:{}};if((i==="determinate"||i==="buffer")&&g!==void 0){u["aria-valuenow"]=Math.round(g),u["aria-valuemin"]=0,u["aria-valuemax"]=100;let n=g-100;$.direction==="rtl"&&(n=-n),d.bar1.transform=`translateX(${n}%)`}if(i==="buffer"&&y!==void 0){let n=(y||0)-100;$.direction==="rtl"&&(n=-n),d.bar2.transform=`translateX(${n}%)`}return U(J,s({className:O(f.root,m),ownerState:c,role:"progressbar"},u,{ref:a},R,{children:[i==="buffer"?p(Q,{className:f.dashed,ownerState:c}):null,p(V,{className:f.bar1,ownerState:c,style:d.bar1}),i==="determinate"?null:p(Y,{className:f.bar2,ownerState:c,style:d.bar2})]}))}),ar=Z;export{ar as L,er as l};

View File

@@ -1,28 +0,0 @@
import{a as F,g as W,C as D,s as v,b as u,_ as r,E as U,r as L,u as N,e as z,j as h,h as j,i as G,G as K,f as B}from"./index.b0a49137.js";import{g as T,a as V,c as Z}from"./generateUtilityClasses.06032f54.js";import{u as q}from"./useId.c3f149cd.js";function A(t){return F("MuiCircularProgress",t)}W("MuiCircularProgress",["root","determinate","indeterminate","colorPrimary","colorSecondary","svg","circle","circleDeterminate","circleIndeterminate","circleDisableShrink"]);const H=["className","color","disableShrink","size","style","thickness","value","variant"];let $=t=>t,M,R,S,E;const g=44,J=D(M||(M=$`
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
`)),O=D(R||(R=$`
0% {
stroke-dasharray: 1px, 200px;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 100px, 200px;
stroke-dashoffset: -15px;
}
100% {
stroke-dasharray: 100px, 200px;
stroke-dashoffset: -125px;
}
`)),Q=t=>{const{classes:o,variant:i,color:a,disableShrink:e}=t,c={root:["root",i,`color${u(a)}`],svg:["svg"],circle:["circle",`circle${u(i)}`,e&&"circleDisableShrink"]};return G(c,A,o)},X=v("span",{name:"MuiCircularProgress",slot:"Root",overridesResolver:(t,o)=>{const{ownerState:i}=t;return[o.root,o[i.variant],o[`color${u(i.color)}`]]}})(({ownerState:t,theme:o})=>r({display:"inline-block"},t.variant==="determinate"&&{transition:o.transitions.create("transform")},t.color!=="inherit"&&{color:(o.vars||o).palette[t.color].main}),({ownerState:t})=>t.variant==="indeterminate"&&U(S||(S=$`
animation: ${0} 1.4s linear infinite;
`),J)),Y=v("svg",{name:"MuiCircularProgress",slot:"Svg",overridesResolver:(t,o)=>o.svg})({display:"block"}),w=v("circle",{name:"MuiCircularProgress",slot:"Circle",overridesResolver:(t,o)=>{const{ownerState:i}=t;return[o.circle,o[`circle${u(i.variant)}`],i.disableShrink&&o.circleDisableShrink]}})(({ownerState:t,theme:o})=>r({stroke:"currentColor"},t.variant==="determinate"&&{transition:o.transitions.create("stroke-dashoffset")},t.variant==="indeterminate"&&{strokeDasharray:"80px, 200px",strokeDashoffset:0}),({ownerState:t})=>t.variant==="indeterminate"&&!t.disableShrink&&U(E||(E=$`
animation: ${0} 1.4s ease-in-out infinite;
`),O)),oo=L.exports.forwardRef(function(o,i){const a=N({props:o,name:"MuiCircularProgress"}),{className:e,color:c="primary",disableShrink:C=!1,size:l=40,style:I,thickness:p=3.6,value:m=0,variant:P="indeterminate"}=a,x=z(a,H),d=r({},a,{color:c,disableShrink:C,size:l,thickness:p,value:m,variant:P}),n=Q(d),f={},y={},k={};if(P==="determinate"){const b=2*Math.PI*((g-p)/2);f.strokeDasharray=b.toFixed(3),k["aria-valuenow"]=Math.round(m),f.strokeDashoffset=`${((100-m)/100*b).toFixed(3)}px`,y.transform="rotate(-90deg)"}return h(X,r({className:j(n.root,e),style:r({width:l,height:l},y,I),ownerState:d,ref:i,role:"progressbar"},k,x,{children:h(Y,{className:n.svg,ownerState:d,viewBox:`${g/2} ${g/2} ${g} ${g}`,children:h(w,{className:n.circle,style:f,ownerState:d,cx:g,cy:g,r:(g-p)/2,fill:"none",strokeWidth:p})})}))}),to=oo;function io(t){return V("MuiLoadingButton",t)}const ao=T("MuiLoadingButton",["root","loading","loadingIndicator","loadingIndicatorCenter","loadingIndicatorStart","loadingIndicatorEnd","endIconLoadingEnd","startIconLoadingStart"]),s=ao,ro=["children","disabled","id","loading","loadingIndicator","loadingPosition","variant"],no=t=>{const{loading:o,loadingPosition:i,classes:a}=t,e={root:["root",o&&"loading"],startIcon:[o&&`startIconLoading${u(i)}`],endIcon:[o&&`endIconLoading${u(i)}`],loadingIndicator:["loadingIndicator",o&&`loadingIndicator${u(i)}`]},c=Z(e,io,a);return r({},a,c)},so=t=>t!=="ownerState"&&t!=="theme"&&t!=="sx"&&t!=="as"&&t!=="classes",eo=v(K,{shouldForwardProp:t=>so(t)||t==="classes",name:"MuiLoadingButton",slot:"Root",overridesResolver:(t,o)=>[o.root,o.startIconLoadingStart&&{[`& .${s.startIconLoadingStart}`]:o.startIconLoadingStart},o.endIconLoadingEnd&&{[`& .${s.endIconLoadingEnd}`]:o.endIconLoadingEnd}]})(({ownerState:t,theme:o})=>r({[`& .${s.startIconLoadingStart}, & .${s.endIconLoadingEnd}`]:{transition:o.transitions.create(["opacity"],{duration:o.transitions.duration.short}),opacity:0}},t.loadingPosition==="center"&&{transition:o.transitions.create(["background-color","box-shadow","border-color"],{duration:o.transitions.duration.short}),[`&.${s.loading}`]:{color:"transparent"}},t.loadingPosition==="start"&&t.fullWidth&&{[`& .${s.startIconLoadingStart}, & .${s.endIconLoadingEnd}`]:{transition:o.transitions.create(["opacity"],{duration:o.transitions.duration.short}),opacity:0,marginRight:-8}},t.loadingPosition==="end"&&t.fullWidth&&{[`& .${s.startIconLoadingStart}, & .${s.endIconLoadingEnd}`]:{transition:o.transitions.create(["opacity"],{duration:o.transitions.duration.short}),opacity:0,marginLeft:-8}})),_=v("div",{name:"MuiLoadingButton",slot:"LoadingIndicator",overridesResolver:(t,o)=>{const{ownerState:i}=t;return[o.loadingIndicator,o[`loadingIndicator${u(i.loadingPosition)}`]]}})(({theme:t,ownerState:o})=>r({position:"absolute",visibility:"visible",display:"flex"},o.loadingPosition==="start"&&(o.variant==="outlined"||o.variant==="contained")&&{left:o.size==="small"?10:14},o.loadingPosition==="start"&&o.variant==="text"&&{left:6},o.loadingPosition==="center"&&{left:"50%",transform:"translate(-50%)",color:t.palette.action.disabled},o.loadingPosition==="end"&&(o.variant==="outlined"||o.variant==="contained")&&{right:o.size==="small"?10:14},o.loadingPosition==="end"&&o.variant==="text"&&{right:6},o.loadingPosition==="start"&&o.fullWidth&&{position:"relative",left:-10},o.loadingPosition==="end"&&o.fullWidth&&{position:"relative",right:-10})),co=L.exports.forwardRef(function(o,i){const a=N({props:o,name:"MuiLoadingButton"}),{children:e,disabled:c=!1,id:C,loading:l=!1,loadingIndicator:I,loadingPosition:p="center",variant:m="text"}=a,P=z(a,ro),x=q(C),d=I!=null?I:h(to,{"aria-labelledby":x,color:"inherit",size:16}),n=r({},a,{disabled:c,loading:l,loadingIndicator:d,loadingPosition:p,variant:m}),f=no(n);return h(eo,r({disabled:c||l,id:x,ref:i},P,{variant:m,classes:f,ownerState:n,children:n.loadingPosition==="end"?B(L.exports.Fragment,{children:[e,l&&h(_,{className:f.loadingIndicator,ownerState:n,children:d})]}):B(L.exports.Fragment,{children:[l&&h(_,{className:f.loadingIndicator,ownerState:n,children:d}),e]})}))}),fo=co;export{fo as L};

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{r as c,f as a,F as i,W as x,j as e,B as d}from"./index.b0a49137.js";const f=c.exports.forwardRef(({children:r,title:s="",meta:t,...o},n)=>a(i,{children:[a(x,{children:[e("title",{children:`${s} | LinkSehat`}),t]}),e(d,{ref:n,...o,children:r})]})),l=f;export{l as P};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{c,j as a}from"./index.b0a49137.js";const r=c(a("path",{d:"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"}),"Search");export{r as S};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,51 +0,0 @@
import{a as y,g as x,C as b,s as R,_ as o,a6 as _,E as u,r as S,u as $,e as U,j as M,h as A,i as X}from"./index.b0a49137.js";function j(t){return String(t).match(/[\d.\-+]*\s*(.*)/)[1]||""}function N(t){return parseFloat(t)}function B(t){return y("MuiSkeleton",t)}x("MuiSkeleton",["root","text","rectangular","rounded","circular","pulse","wave","withChildren","fitContent","heightAuto"]);const F=["animation","className","component","height","style","variant","width"];let r=t=>t,p,g,m,f;const K=t=>{const{classes:a,variant:e,animation:i,hasChildren:n,width:l,height:s}=t;return X({root:["root",e,i,n&&"withChildren",n&&!l&&"fitContent",n&&!s&&"heightAuto"]},B,a)},P=b(p||(p=r`
0% {
opacity: 1;
}
50% {
opacity: 0.4;
}
100% {
opacity: 1;
}
`)),T=b(g||(g=r`
0% {
transform: translateX(-100%);
}
50% {
/* +0.5s of delay between each loop */
transform: translateX(100%);
}
100% {
transform: translateX(100%);
}
`)),W=R("span",{name:"MuiSkeleton",slot:"Root",overridesResolver:(t,a)=>{const{ownerState:e}=t;return[a.root,a[e.variant],e.animation!==!1&&a[e.animation],e.hasChildren&&a.withChildren,e.hasChildren&&!e.width&&a.fitContent,e.hasChildren&&!e.height&&a.heightAuto]}})(({theme:t,ownerState:a})=>{const e=j(t.shape.borderRadius)||"px",i=N(t.shape.borderRadius);return o({display:"block",backgroundColor:t.vars?t.vars.palette.Skeleton.bg:_(t.palette.text.primary,t.palette.mode==="light"?.11:.13),height:"1.2em"},a.variant==="text"&&{marginTop:0,marginBottom:0,height:"auto",transformOrigin:"0 55%",transform:"scale(1, 0.60)",borderRadius:`${i}${e}/${Math.round(i/.6*10)/10}${e}`,"&:empty:before":{content:'"\\00a0"'}},a.variant==="circular"&&{borderRadius:"50%"},a.variant==="rounded"&&{borderRadius:(t.vars||t).shape.borderRadius},a.hasChildren&&{"& > *":{visibility:"hidden"}},a.hasChildren&&!a.width&&{maxWidth:"fit-content"},a.hasChildren&&!a.height&&{height:"auto"})},({ownerState:t})=>t.animation==="pulse"&&u(m||(m=r`
animation: ${0} 1.5s ease-in-out 0.5s infinite;
`),P),({ownerState:t,theme:a})=>t.animation==="wave"&&u(f||(f=r`
position: relative;
overflow: hidden;
/* Fix bug in Safari https://bugs.webkit.org/show_bug.cgi?id=68196 */
-webkit-mask-image: -webkit-radial-gradient(white, black);
&::after {
animation: ${0} 1.6s linear 0.5s infinite;
background: linear-gradient(
90deg,
transparent,
${0},
transparent
);
content: '';
position: absolute;
transform: translateX(-100%); /* Avoid flash during server-side hydration */
bottom: 0;
left: 0;
right: 0;
top: 0;
}
`),T,(a.vars||a).palette.action.hover)),E=S.exports.forwardRef(function(a,e){const i=$({props:a,name:"MuiSkeleton"}),{animation:n="pulse",className:l,component:s="span",height:h,style:v,variant:C="text",width:k}=i,d=U(i,F),c=o({},i,{animation:n,component:s,variant:C,hasChildren:Boolean(d.children)}),w=K(c);return M(W,o({as:s,ref:e,className:A(w.root,l),ownerState:c},d,{style:o({width:k,height:h},v)}))}),O=E;export{O as S};

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{a as $,g as H,s as x,a3 as W,_ as d,r as A,e as D,ao as G,H as J,f as K,j as M,h as Q,b as T,i as V}from"./index.b0a49137.js";function X(e){return $("PrivateSwitchBase",e)}H("PrivateSwitchBase",["root","checked","disabled","input","edgeStart","edgeEnd"]);const Y=["autoFocus","checked","checkedIcon","className","defaultChecked","disabled","disableFocusRipple","edge","icon","id","inputProps","inputRef","name","onBlur","onChange","onFocus","readOnly","required","tabIndex","type","value"],Z=e=>{const{classes:a,checked:i,disabled:l,edge:o}=e,r={root:["root",i&&"checked",l&&"disabled",o&&`edge${T(o)}`],input:["input"]};return V(r,X,a)},ee=x(W)(({ownerState:e})=>d({padding:9,borderRadius:"50%"},e.edge==="start"&&{marginLeft:e.size==="small"?-3:-12},e.edge==="end"&&{marginRight:e.size==="small"?-3:-12})),se=x("input")({cursor:"inherit",position:"absolute",opacity:0,width:"100%",height:"100%",top:0,left:0,margin:0,padding:0,zIndex:1}),te=A.exports.forwardRef(function(a,i){const{autoFocus:l,checked:o,checkedIcon:r,className:F,defaultChecked:h,disabled:y,disableFocusRipple:p=!1,edge:w=!1,icon:S,id:R,inputProps:I,inputRef:P,name:j,onBlur:f,onChange:g,onFocus:b,readOnly:z,required:N=!1,tabIndex:U,type:c,value:m}=a,_=D(a,Y),[k,q]=G({controlled:o,default:Boolean(h),name:"SwitchBase",state:"checked"}),t=J(),v=s=>{b&&b(s),t&&t.onFocus&&t.onFocus(s)},L=s=>{f&&f(s),t&&t.onBlur&&t.onBlur(s)},O=s=>{if(s.nativeEvent.defaultPrevented)return;const C=s.target.checked;q(C),g&&g(s,C)};let n=y;t&&typeof n>"u"&&(n=t.disabled);const E=c==="checkbox"||c==="radio",u=d({},a,{checked:k,disabled:n,disableFocusRipple:p,edge:w}),B=Z(u);return K(ee,d({component:"span",className:Q(B.root,F),centerRipple:!0,focusRipple:!p,disabled:n,tabIndex:null,role:void 0,onFocus:v,onBlur:L,ownerState:u,ref:i},_,{children:[M(se,d({autoFocus:l,checked:o,defaultChecked:h,className:B.input,disabled:n,id:E?R:void 0,name:j,onChange:O,readOnly:z,ref:P,required:N,ownerState:u,tabIndex:U,type:c},c==="checkbox"&&m===void 0?{}:{value:m},I)),k?r:S]}))}),oe=te;export{oe as S};

View File

@@ -1 +0,0 @@
import{a as u,g as p,s as C,r as m,u as T,e as b,_ as r,j as d,h as f,i as x}from"./index.b0a49137.js";function h(e){return u("MuiTableContainer",e)}p("MuiTableContainer",["root"]);const v=["className","component"],w=e=>{const{classes:s}=e;return x({root:["root"]},h,s)},y=C("div",{name:"MuiTableContainer",slot:"Root",overridesResolver:(e,s)=>s.root})({width:"100%",overflowX:"auto"}),g=m.exports.forwardRef(function(s,t){const o=T({props:s,name:"MuiTableContainer"}),{className:i,component:a="div"}=o,l=b(o,v),n=r({},o,{component:a}),c=w(n);return d(y,r({ref:t,as:a,className:f(c.root,i),ownerState:n},l))}),R=g;export{R as T};

View File

@@ -1 +0,0 @@
import{a as u,g as m,s as b,r as T,u as h,e as H,_ as l,j as n,h as f,i as v}from"./index.b0a49137.js";import{d as x}from"./TableRow.41459f01.js";function C(e){return u("MuiTableHead",e)}m("MuiTableHead",["root"]);const g=["className","component"],y=e=>{const{classes:s}=e;return v({root:["root"]},C,s)},w=b("thead",{name:"MuiTableHead",slot:"Root",overridesResolver:(e,s)=>s.root})({display:"table-header-group"}),M={variant:"head"},c="thead",R=T.exports.forwardRef(function(s,a){const o=h({props:s,name:"MuiTableHead"}),{className:d,component:t=c}=o,i=H(o,g),r=l({},o,{component:t}),p=y(r);return n(x.Provider,{value:M,children:n(w,l({as:t,className:f(p.root,d),ref:a,role:t===c?null:"rowgroup",ownerState:r},i))})}),j=R;export{j as T};

View File

@@ -1 +0,0 @@
import{r as n,f as h,F as c,j as o,I as p,q as u,af as d}from"./index.b0a49137.js";function f({actions:t,disableRipple:a}){const[r,e]=n.exports.useState(null);n.exports.useEffect(()=>{e(null)},[t]);const i=s=>{e(s.currentTarget)},l=()=>{e(null)};return h(c,{children:[o(p,{onClick:i,disableRipple:a,children:o(u,{icon:"eva:more-vertical-fill",width:20,height:20})}),o(d,{open:Boolean(r),anchorEl:r,onClose:l,anchorOrigin:{vertical:"top",horizontal:"left"},transformOrigin:{vertical:"top",horizontal:"right"},arrow:"right-top",sx:{mt:-1,width:"auto",minWidth:160,"& .MuiMenuItem-root":{px:1,typography:"body2",borderRadius:.75,"& svg":{mr:2,width:20,height:20}}},children:t}),"\xA0\xA0\xA0\xA0"]})}export{f as T};

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +0,0 @@
import{r as c,a as m,g as $,s as R,_ as i,u as h,e as k,j as y,h as w,i as H,b as u,l as W,a6 as T,d as L}from"./index.b0a49137.js";const I=c.exports.createContext(),j=I;function J(e){return m("MuiTable",e)}$("MuiTable",["root","stickyHeader"]);const q=["className","component","padding","size","stickyHeader"],E=e=>{const{classes:o,stickyHeader:t}=e;return H({root:["root",t&&"stickyHeader"]},J,o)},F=R("table",{name:"MuiTable",slot:"Root",overridesResolver:(e,o)=>{const{ownerState:t}=e;return[o.root,t.stickyHeader&&o.stickyHeader]}})(({theme:e,ownerState:o})=>i({display:"table",width:"100%",borderCollapse:"collapse",borderSpacing:0,"& caption":i({},e.typography.body2,{padding:e.spacing(2),color:(e.vars||e).palette.text.secondary,textAlign:"left",captionSide:"bottom"})},o.stickyHeader&&{borderCollapse:"separate"})),A="table",G=c.exports.forwardRef(function(o,t){const a=h({props:o,name:"MuiTable"}),{className:r,component:s=A,padding:l="normal",size:n="medium",stickyHeader:d=!1}=a,b=k(a,q),p=i({},a,{component:s,padding:l,size:n,stickyHeader:d}),v=E(p),M=c.exports.useMemo(()=>({padding:l,size:n,stickyHeader:d}),[l,n,d]);return y(j.Provider,{value:M,children:y(F,i({as:s,role:s===A?null:"table",ref:t,className:w(v.root,r),ownerState:p},b))})}),ye=G,K=c.exports.createContext(),z=K;function Q(e){return m("MuiTableBody",e)}$("MuiTableBody",["root"]);const V=["className","component"],X=e=>{const{classes:o}=e;return H({root:["root"]},Q,o)},Y=R("tbody",{name:"MuiTableBody",slot:"Root",overridesResolver:(e,o)=>o.root})({display:"table-row-group"}),Z={variant:"body"},_="tbody",ee=c.exports.forwardRef(function(o,t){const a=h({props:o,name:"MuiTableBody"}),{className:r,component:s=_}=a,l=k(a,V),n=i({},a,{component:s}),d=X(n);return y(z.Provider,{value:Z,children:y(Y,i({className:w(d.root,r),as:s,ref:t,role:s===_?null:"rowgroup",ownerState:n},l))})}),ve=ee;function oe(e){return m("MuiTableCell",e)}const te=$("MuiTableCell",["root","head","body","footer","sizeSmall","sizeMedium","paddingCheckbox","paddingNone","alignLeft","alignCenter","alignRight","alignJustify","stickyHeader"]),ae=te,se=["align","className","component","padding","scope","size","sortDirection","variant"],le=e=>{const{classes:o,variant:t,align:a,padding:r,size:s,stickyHeader:l}=e,n={root:["root",t,l&&"stickyHeader",a!=="inherit"&&`align${u(a)}`,r!=="normal"&&`padding${u(r)}`,`size${u(s)}`]};return H(n,oe,o)},re=R("td",{name:"MuiTableCell",slot:"Root",overridesResolver:(e,o)=>{const{ownerState:t}=e;return[o.root,o[t.variant],o[`size${u(t.size)}`],t.padding!=="normal"&&o[`padding${u(t.padding)}`],t.align!=="inherit"&&o[`align${u(t.align)}`],t.stickyHeader&&o.stickyHeader]}})(({theme:e,ownerState:o})=>i({},e.typography.body2,{display:"table-cell",verticalAlign:"inherit",borderBottom:e.vars?`1px solid ${e.vars.palette.TableCell.border}`:`1px solid
${e.palette.mode==="light"?W(T(e.palette.divider,1),.88):L(T(e.palette.divider,1),.68)}`,textAlign:"left",padding:16},o.variant==="head"&&{color:(e.vars||e).palette.text.primary,lineHeight:e.typography.pxToRem(24),fontWeight:e.typography.fontWeightMedium},o.variant==="body"&&{color:(e.vars||e).palette.text.primary},o.variant==="footer"&&{color:(e.vars||e).palette.text.secondary,lineHeight:e.typography.pxToRem(21),fontSize:e.typography.pxToRem(12)},o.size==="small"&&{padding:"6px 16px",[`&.${ae.paddingCheckbox}`]:{width:24,padding:"0 12px 0 16px","& > *":{padding:0}}},o.padding==="checkbox"&&{width:48,padding:"0 0 0 4px"},o.padding==="none"&&{padding:0},o.align==="left"&&{textAlign:"left"},o.align==="center"&&{textAlign:"center"},o.align==="right"&&{textAlign:"right",flexDirection:"row-reverse"},o.align==="justify"&&{textAlign:"justify"},o.stickyHeader&&{position:"sticky",top:0,zIndex:2,backgroundColor:(e.vars||e).palette.background.default})),ne=c.exports.forwardRef(function(o,t){const a=h({props:o,name:"MuiTableCell"}),{align:r="inherit",className:s,component:l,padding:n,scope:d,size:b,sortDirection:p,variant:v}=a,M=k(a,se),g=c.exports.useContext(j),x=c.exports.useContext(z),N=x&&x.variant==="head";let f;l?f=l:f=N?"th":"td";let C=d;f==="td"?C=void 0:!C&&N&&(C="col");const B=v||x&&x.variant,U=i({},a,{align:r,component:f,padding:n||(g&&g.padding?g.padding:"normal"),size:b||(g&&g.size?g.size:"medium"),sortDirection:p,stickyHeader:B==="head"&&g&&g.stickyHeader,variant:B}),D=le(U);let P=null;return p&&(P=p==="asc"?"ascending":"descending"),y(re,i({as:f,ref:t,className:w(D.root,s),"aria-sort":P,scope:C,ownerState:U},M))}),fe=ne;function ie(e){return m("MuiTableRow",e)}const ce=$("MuiTableRow",["root","selected","hover","head","footer"]),O=ce,de=["className","component","hover","selected"],pe=e=>{const{classes:o,selected:t,hover:a,head:r,footer:s}=e;return H({root:["root",t&&"selected",a&&"hover",r&&"head",s&&"footer"]},ie,o)},be=R("tr",{name:"MuiTableRow",slot:"Root",overridesResolver:(e,o)=>{const{ownerState:t}=e;return[o.root,t.head&&o.head,t.footer&&o.footer]}})(({theme:e})=>({color:"inherit",display:"table-row",verticalAlign:"middle",outline:0,[`&.${O.hover}:hover`]:{backgroundColor:(e.vars||e).palette.action.hover},[`&.${O.selected}`]:{backgroundColor:e.vars?`rgba(${e.vars.palette.primary.mainChannel} / ${e.vars.palette.action.selectedOpacity})`:T(e.palette.primary.main,e.palette.action.selectedOpacity),"&:hover":{backgroundColor:e.vars?`rgba(${e.vars.palette.primary.mainChannel} / calc(${e.vars.palette.action.selectedOpacity} + ${e.vars.palette.action.hoverOpacity}))`:T(e.palette.primary.main,e.palette.action.selectedOpacity+e.palette.action.hoverOpacity)}}})),S="tr",ge=c.exports.forwardRef(function(o,t){const a=h({props:o,name:"MuiTableRow"}),{className:r,component:s=S,hover:l=!1,selected:n=!1}=a,d=k(a,de),b=c.exports.useContext(z),p=i({},a,{component:s,hover:l,selected:n,head:b&&b.variant==="head",footer:b&&b.variant==="footer"}),v=pe(p);return y(be,i({as:s,ref:t,className:w(v.root,r),role:s===S?null:"row",ownerState:p},d))}),xe=ge;export{ye as T,ve as a,xe as b,fe as c,z as d};

View File

@@ -1 +0,0 @@
import{g as q,a as S,s as N,b as L,_ as l,r as U,u as _,e as B,H as se,K as le,j as c,h as W,i as j,M as ae,f as ie,N as ne,Q as de,U as ue,V as ce,O as pe}from"./index.b0a49137.js";import{u as fe}from"./useId.c3f149cd.js";function me(e){return S("MuiFormHelperText",e)}const xe=q("MuiFormHelperText",["root","error","disabled","sizeSmall","sizeMedium","contained","focused","filled","required"]),M=xe;var $;const Fe=["children","className","component","disabled","error","filled","focused","margin","required","variant"],he=e=>{const{classes:o,contained:t,size:s,disabled:i,error:n,filled:d,focused:p,required:u}=e,r={root:["root",i&&"disabled",n&&"error",s&&`size${L(s)}`,t&&"contained",p&&"focused",d&&"filled",u&&"required"]};return j(r,me,o)},be=N("p",{name:"MuiFormHelperText",slot:"Root",overridesResolver:(e,o)=>{const{ownerState:t}=e;return[o.root,t.size&&o[`size${L(t.size)}`],t.contained&&o.contained,t.filled&&o.filled]}})(({theme:e,ownerState:o})=>l({color:(e.vars||e).palette.text.secondary},e.typography.caption,{textAlign:"left",marginTop:3,marginRight:0,marginBottom:0,marginLeft:0,[`&.${M.disabled}`]:{color:(e.vars||e).palette.text.disabled},[`&.${M.error}`]:{color:(e.vars||e).palette.error.main}},o.size==="small"&&{marginTop:4},o.contained&&{marginLeft:14,marginRight:14})),Te=U.exports.forwardRef(function(o,t){const s=_({props:o,name:"MuiFormHelperText"}),{children:i,className:n,component:d="p"}=s,p=B(s,Fe),u=se(),r=le({props:s,muiFormControl:u,states:["variant","size","disabled","error","filled","focused","required"]}),f=l({},s,{component:d,contained:r.variant==="filled"||r.variant==="outlined",variant:r.variant,size:r.size,disabled:r.disabled,error:r.error,filled:r.filled,focused:r.focused,required:r.required}),F=he(f);return c(be,l({as:d,ownerState:f,className:W(F.root,n),ref:t},p,{children:i===" "?$||($=c("span",{className:"notranslate",children:"\u200B"})):i}))}),ve=Te;function Ce(e){return S("MuiTextField",e)}q("MuiTextField",["root"]);const ge=["autoComplete","autoFocus","children","className","color","defaultValue","disabled","error","FormHelperTextProps","fullWidth","helperText","id","InputLabelProps","inputProps","InputProps","inputRef","label","maxRows","minRows","multiline","name","onBlur","onChange","onFocus","placeholder","required","rows","select","SelectProps","type","value","variant"],Re={standard:ue,filled:ce,outlined:pe},we=e=>{const{classes:o}=e;return j({root:["root"]},Ce,o)},ye=N(ae,{name:"MuiTextField",slot:"Root",overridesResolver:(e,o)=>o.root})({}),Ie=U.exports.forwardRef(function(o,t){const s=_({props:o,name:"MuiTextField"}),{autoComplete:i,autoFocus:n=!1,children:d,className:p,color:u="primary",defaultValue:r,disabled:f=!1,error:F=!1,FormHelperTextProps:V,fullWidth:T=!1,helperText:v,id:O,InputLabelProps:h,inputProps:k,InputProps:A,inputRef:E,label:m,maxRows:K,minRows:Q,multiline:w=!1,name:D,onBlur:G,onChange:J,onFocus:X,placeholder:Y,required:y=!1,rows:Z,select:C=!1,SelectProps:g,type:ee,value:I,variant:b="outlined"}=s,oe=B(s,ge),H=l({},s,{autoFocus:n,color:u,disabled:f,error:F,fullWidth:T,multiline:w,required:y,select:C,variant:b}),re=we(H),x={};b==="outlined"&&(h&&typeof h.shrink<"u"&&(x.notched=h.shrink),x.label=m),C&&((!g||!g.native)&&(x.id=void 0),x["aria-describedby"]=void 0);const a=fe(O),R=v&&a?`${a}-helper-text`:void 0,P=m&&a?`${a}-label`:void 0,te=Re[b],z=c(te,l({"aria-describedby":R,autoComplete:i,autoFocus:n,defaultValue:r,fullWidth:T,multiline:w,name:D,rows:Z,maxRows:K,minRows:Q,type:ee,value:I,id:a,inputRef:E,onBlur:G,onChange:J,onFocus:X,placeholder:Y,inputProps:k},x,A));return ie(ye,l({className:W(re.root,p),disabled:f,error:F,fullWidth:T,ref:t,required:y,color:u,variant:b,ownerState:H},oe,{children:[m!=null&&m!==""&&c(ne,l({htmlFor:a,id:P},h,{children:m})),C?c(de,l({"aria-describedby":R,id:a,labelId:P,value:I,input:z},g,{children:d})):z,v&&c(ve,l({id:R},V,{children:v}))]}))}),ze=Ie;export{ve as F,ze as T};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.