Merge remote-tracking branch 'refs/remotes/origin/staging' into staging

This commit is contained in:
kevin
2023-08-09 09:40:49 +07:00
50 changed files with 1083 additions and 164 deletions

View File

@@ -0,0 +1,21 @@
<?php
namespace Modules\HospitalPortal\Helpers;
class ApiResponse
{
public static function apiResponse(string $status, array|object $data = null, string|array|object $message = null, int $statusCode)
{
if ($message instanceof \Illuminate\Support\MessageBag) {
$message = $message->first();
}
return response()->json([
'meta' => [
'status' => $status,
'code' => $statusCode,
'message' => $message
],
'data' => $data,
], $statusCode);
}
}

View File

@@ -12,33 +12,48 @@ use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
use Modules\Internal\Emails\SendVerifyEmail; use Modules\Internal\Emails\SendVerifyEmail;
use Modules\Internal\Events\ForgetPassword; use Modules\Internal\Events\ForgetPassword;
use Illuminate\Support\Facades\Validator;
use Modules\HospitalPortal\Helpers\ApiResponse;
class AuthController extends Controller class AuthController extends Controller
{ {
public function login(Request $request) public function login(Request $request)
{ {
$request->validate([ $data = [
'email' => $request->email,
'password' => $request->password
];
$validator = Validator::make($request->all(), [
'email' => 'required|email', 'email' => 'required|email',
'password' => 'required' 'password' => 'required'
], [
'email.required' => trans('validation.required',['attribute' => 'Email']),
'email.email' => trans('validation.email'),
'password.required' => trans('validation.required',['attribute' => 'Password']),
]); ]);
$user = User::query() if ($validator->fails())
->where('email', $request->email) {
->first(); return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
if (!$user) {
return response(['message' => 'User Tidak Ditemukan'], 404);
} }
else
{
$user = User::where('email', $request->email)->first();
if (!$user) {
return ApiResponse::apiResponse('Not Found', $data, trans('message.not_found'), 404);
}
if (!Hash::check($request->password, $user->password)) { if (!Hash::check($request->password, $user->password)) {
return response(['message' => 'Password Salah'], 403); return ApiResponse::apiResponse('Bad Request', $data, trans('message.password'), 400);
}
$res_data = [
'user' => $user,
'token' => $user->createToken('app')->plainTextToken
];
return ApiResponse::apiResponse("Success", $res_data, trans('message.success'), 200);
} }
return response([
'message' => 'Selamat Datang',
'user' => $user,
'token' => $user->createToken('app')->plainTextToken
]);
} }
public function logout(Request $request) public function logout(Request $request)

View File

@@ -108,7 +108,7 @@ class ClaimRequestController extends Controller
} }
} }
if ($request->hasFile('result_files')) { if ($request->hasFile('kondisi_files')) {
foreach ($request->result_files as $file) { foreach ($request->result_files as $file) {
$pathFile = File::storeFile('claim-kondisi', $newClaimRequest->id, $file); $pathFile = File::storeFile('claim-kondisi', $newClaimRequest->id, $file);
$newClaimRequest->files()->updateOrCreate([ $newClaimRequest->files()->updateOrCreate([

View File

@@ -7,6 +7,8 @@ use App\Models\Member;
use Illuminate\Contracts\Support\Renderable; use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Routing\Controller; use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Validator;
use Modules\HospitalPortal\Helpers\ApiResponse;
class MemberController extends Controller class MemberController extends Controller
{ {
@@ -16,26 +18,37 @@ class MemberController extends Controller
*/ */
public function search(Request $request) public function search(Request $request)
{ {
$request->validate([ $data = [
'no_polis' => $request->no_polis,
'birth_date' => $request->birth_date
];
$validator = Validator::make($request->all(), [
'no_polis' => 'required', 'no_polis' => 'required',
'birth_date' => 'required' 'birth_date' => 'required'
], [
'no_polis.required' => trans('validation.required',['attribute' => 'Member ID']),
'birth_date.required' => trans('validation.required',['attribute' => 'Birth Date']),
]); ]);
if ($validator->fails())
$member = Member::query() {
->where('member_id', $request->no_polis) return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
->where('birth_date', $request->birth_date) }
->with(['person', 'currentCorporate', else
// 'currentCorporate.corporateServices' => function ($corporateService) { {
// $corporateService->where('status', 'active'); $res_data = Member::query()
// }, ->where('member_id', $request->no_polis)
// 'currentCorporate.corporateServices.service' ->where('birth_date', $request->birth_date)
// 'currentPlan.benefits', ->with(['person', 'currentCorporate',
// 'currentPlan.corporateBenefit.plan', // 'currentCorporate.corporateServices' => function ($corporateService) {
'currentPlan.corporateBenefits.benefit' // $corporateService->where('status', 'active');
]) // },
->firstOrFail(); // 'currentCorporate.corporateServices.service'
// 'currentPlan.benefits',
// 'currentPlan.corporateBenefit.plan',
return Helper::responseJson($member); 'currentPlan.corporateBenefits.benefit'
])
->firstOrFail();
return ApiResponse::apiResponse("Success", $res_data, trans('message.success'), 200);
}
} }
} }

View File

@@ -0,0 +1,65 @@
<?php
namespace Modules\HospitalPortal\Http\Middleware;
use Modules\HospitalPortal\Helpers\ApiResponse;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Facades\App;
class Authentication
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$acceptHeader = $request->header('Accept');
$contentType = $request->header('Content-Type');
$locale = $request->header('Accept-Language');
// Add language
if(!$locale)
{
return ApiResponse::apiResponse('Unauthorized', null, trans('validation.required', ['attribute' => 'Accept-Language']), 401);
}
if($locale !== 'en-US' && $locale !== 'id-ID')
{
return ApiResponse::apiResponse('Bad Request', null, trans('validation.invalid', ['attribute' => 'Accept-Language']), 400);
}
if ($locale === 'en-US')
{
App::setLocale('en');
} elseif ($locale === 'id-ID')
{
App::setLocale('id');
} else
{
App::setLocale('en');
}
// Validate type accept & content type
if (!$acceptHeader)
{
return ApiResponse::apiResponse('Unauthorized', null, trans('validation.required', ['attribute' => 'Accept']), 401);
}
if (!$contentType)
{
return ApiResponse::apiResponse('Unauthorized', null, trans('validation.required', ['attribute' => 'Content-Type']), 401);
}
if ($acceptHeader !== 'application/json')
{
return ApiResponse::apiResponse('Bad Request', null, trans('validation.invalid', ['attribute' => 'Accept']), 400);
}
if($contentType !== 'application/json')
{
return ApiResponse::apiResponse('Bad Request', null, trans('validation.invalid', ['attribute' => 'Content-Type']), 400);
}
return $next($request);
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace Modules\HospitalPortal\Http\Middleware;
use Modules\HospitalPortal\Helpers\ApiResponse;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Facades\App;
class Authorization
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$acceptHeader = $request->header('Accept');
$contentType = $request->header('Content-Type');
$locale = $request->header('Accept-Language');
$authorization = $request->header('Authorization');
// Add language
if(!$locale)
{
return ApiResponse::apiResponse('Unauthorized', null, trans('validation.required', ['attribute' => 'Accept-Language']), 401);
}
if($locale !== 'en-US' && $locale !== 'id-ID')
{
return ApiResponse::apiResponse('Bad Request', null, trans('validation.invalid', ['attribute' => 'Accept-Language']), 400);
}
if ($locale === 'en-US')
{
App::setLocale('en');
} elseif ($locale === 'id-ID')
{
App::setLocale('id');
} else
{
App::setLocale('en');
}
// Validate authorization
if (empty($authorization) || strpos($authorization, 'Bearer ') !== 0) {
return ApiResponse::apiResponse('Unauthorized', null, trans('validation.required', ['attribute' => 'Authorization']), 401);
}
// Validate type accept & content type
if (!$acceptHeader)
{
return ApiResponse::apiResponse('Unauthorized', null, trans('validation.required', ['attribute' => 'Accept']), 401);
}
if (!$contentType)
{
return ApiResponse::apiResponse('Unauthorized', null, trans('validation.required', ['attribute' => 'Content-Type']), 401);
}
if ($acceptHeader !== 'application/json')
{
return ApiResponse::apiResponse('Bad Request', null, trans('validation.invalid', ['attribute' => 'Accept']), 400);
}
if($contentType !== 'application/json')
{
return ApiResponse::apiResponse('Bad Request', null, trans('validation.invalid', ['attribute' => 'Content-Type']), 400);
}
return $next($request);
}
}

View File

@@ -5,6 +5,8 @@ use Modules\HospitalPortal\Http\Controllers\Api\AuthController;
use Modules\HospitalPortal\Http\Controllers\Api\ClaimRequestController; use Modules\HospitalPortal\Http\Controllers\Api\ClaimRequestController;
use Modules\HospitalPortal\Http\Controllers\Api\MemberController; use Modules\HospitalPortal\Http\Controllers\Api\MemberController;
use Modules\HospitalPortal\Http\Controllers\ClaimController; use Modules\HospitalPortal\Http\Controllers\ClaimController;
use Modules\HospitalPortal\Http\Middleware\Authentication;
use Modules\HospitalPortal\Http\Middleware\Authorization;
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@@ -16,29 +18,39 @@ use Modules\HospitalPortal\Http\Controllers\ClaimController;
| is assigned the "api" middleware group. Enjoy building your API! | is assigned the "api" middleware group. Enjoy building your API!
| |
*/ */
Route::prefix('v1')->group(function() {
Route::prefix('hospitalportal')->group(function () {
Route::prefix('hospitalportal')->group(function () { Route::middleware(Authentication::class)->group(function () {
Route::controller(AuthController::class)->group(function () {
Route::post('login', [AuthController::class, 'login'])->name('login'); Route::post('login', 'login');
Route::post('forget-password', [AuthController::class, 'forgetPassword'])->name('forget-password'); });
Route::post('verify-email', [AuthController::class, 'verifyEmail'])->name('verify-email');
Route::middleware('auth:sanctum')->group(function () {
Route::post('logout', [AuthController::class, 'logout'])->name('logout');
Route::get('/user', function (Request $request) {
return $request->user();
}); });
Route::put('reset-password', [AuthController::class, 'resetPassword'])->name('resetPassword');
//Route::post('forget-password', [AuthController::class, 'forgetPassword'])->name('forget-password');
//Route::post('verify-email', [AuthController::class, 'verifyEmail'])->name('verify-email');
Route::get('claims', [ClaimController::class, 'index']);
Route::post('search-member', [MemberController::class, 'search']); Route::middleware('auth:sanctum')->group(function () {
Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index'); Route::post('logout', [AuthController::class, 'logout'])->name('logout');
Route::post('claim-requests', [ClaimRequestController::class, 'store'])->name('claim-requests.store'); Route::get('/user', function (Request $request) {
Route::get('claim-requests/{claim_request_id}/log', [ClaimRequestController::class, 'generateLog'])->name('claim-requests.generate-log'); return $request->user();
Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show'); });
Route::put('reset-password', [AuthController::class, 'resetPassword'])->name('resetPassword');
Route::get('claims', [ClaimController::class, 'index']);
Route::middleware(Authorization::class)->group(function () {
Route::controller(MemberController::class)->group(function () {
Route::post('search-member', 'search');
});
});
Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index');
Route::post('claim-requests', [ClaimRequestController::class, 'store'])->name('claim-requests.store');
Route::get('claim-requests/{claim_request_id}/log', [ClaimRequestController::class, 'generateLog'])->name('claim-requests.generate-log');
Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show');
});
}); });
}); });

View File

@@ -10,6 +10,8 @@ use Illuminate\Http\Request;
use Illuminate\Routing\Controller; use Illuminate\Routing\Controller;
use Modules\Internal\Transformers\ClaimRequestResource; use Modules\Internal\Transformers\ClaimRequestResource;
use Modules\Internal\Transformers\ClaimRequestShowResource; use Modules\Internal\Transformers\ClaimRequestShowResource;
use App\Models\File;
use App\Models\FilesMcu;
class ClaimRequestController extends Controller class ClaimRequestController extends Controller
{ {
@@ -140,4 +142,29 @@ class ClaimRequestController extends Controller
return $claimRequest; return $claimRequest;
} }
public function filesMcu(Request $request)
{
$request->validate([
'id' => 'required',
'memberid' => 'required'
]);
if ($request->hasFile('result_files')) {
$pathFile = File::storeFile('claim-result', $request->id, $request->result_files);
$data = [
'memberid' => $request->id,
'original_name' => $request->result_files->getClientOriginalName(),
'path' => $pathFile,
'created_by' => auth()->user()->id,
'updated_by' => auth()->user()->id
];
FilesMcu::create($data);
return Helper::responseJson(data: $request->toArray(), message: 'Berhasil tambah file MemberID '.$request->memberid.', silahkan lihat dilaporan');
}
else
{
return Helper::responseJson(data: $request->toArray(), message: 'Tidak ada file member yang ditambahkan');
}
}
} }

View File

@@ -18,6 +18,8 @@ use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Modules\Internal\Services\MemberEnrollmentService; use Modules\Internal\Services\MemberEnrollmentService;
use PDF; use PDF;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Builder;
class CorporateMemberController extends Controller class CorporateMemberController extends Controller
{ {
@@ -32,11 +34,8 @@ class CorporateMemberController extends Controller
public function index(Request $request, $corporate_id) public function index(Request $request, $corporate_id)
{ {
$members = Member::query() $members = Member::query()
->filter($request->all()) ->joinCorporateEmployees('left')
// ->where('corporate_id', $corporate_id) ->where('corporate_employees.corporate_id', $corporate_id)
->whereHas('employeds', function ($employeds) use ($corporate_id) {
$employeds->where('corporate_id', $corporate_id);
})
->with([ ->with([
'employeds', 'employeds',
'currentPolicy', 'currentPolicy',
@@ -54,6 +53,14 @@ class CorporateMemberController extends Controller
]); ]);
} }
]) ])
->when($request->input('search'), function (Builder $query, $search) {
$query->where(function (Builder $query) use ($search) {
$query->orWhere('members.member_id', 'like', "%" . $search . "%")
->orWhere('members.name', 'like', "%" . $search . "%");
});
})
->select('members.*')
->selectRaw('(SELECT GROUP_CONCAT(files_mcu.original_name SEPARATOR ", ") AS file_mcu_names from files_mcu WHERE files_mcu.memberid = members.id) AS file_mcu_names')
->paginate() ->paginate()
->appends($request->all()); ->appends($request->all());
return Helper::paginateResources(MemberDataTableResource::collection($members)); return Helper::paginateResources(MemberDataTableResource::collection($members));

View File

@@ -263,7 +263,7 @@ class ClaimEncounterController extends Controller
} }
} }
public function x`counters($claim_id) public function xcounters($claim_id)
{ {
$claim = Claim::findOrFail($claim_id); $claim = Claim::findOrFail($claim_id);
$encounters = $claim->encounters()->get(); $encounters = $claim->encounters()->get();

View File

@@ -158,7 +158,9 @@ Route::prefix('internal')->group(function () {
Route::resource('doctors', DoctorController::class); Route::resource('doctors', DoctorController::class);
Route::post('generate-log/{member_id}', [CorporateMemberController::class, 'generateLog']); Route::post('generate-log/{member_id}', [CorporateMemberController::class, 'generateLog']);
Route::controller(ClaimRequestController::class)->group(function(){
Route::post('files-mcu','filesMcu');
});
Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index'); Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index');
Route::post('claim-requests/{id}/approve', [ClaimRequestController::class, 'approve'])->name('claim-requests.approve'); Route::post('claim-requests/{id}/approve', [ClaimRequestController::class, 'approve'])->name('claim-requests.approve');
Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show'); Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show');

View File

@@ -11,8 +11,13 @@ use App\Models\CorporatePolicy;
use App\Models\CorporatePlan; use App\Models\CorporatePlan;
use App\Models\Member; use App\Models\Member;
use App\Models\MemberPolicy; use App\Models\MemberPolicy;
use App\Models\MemberPlan;
use App\Models\Person; use App\Models\Person;
use App\Models\Plan; use App\Models\Plan;
use App\Models\OLDLMS\User;
use App\Models\OLDLMS\UserDetail;
use App\Models\OLDLMS\UserInsurance;
use App\Models\OLDLMS\UserInsuranceDetail;
use Box\Spout\Writer\Common\Creator\WriterEntityFactory; use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
use Box\Spout\Common\Entity\Row; use Box\Spout\Common\Entity\Row;
use Carbon\Carbon; use Carbon\Carbon;
@@ -565,6 +570,7 @@ class MemberEnrollmentService
"policy_in_force" => $row['policy_in_force'] ?? null, "policy_in_force" => $row['policy_in_force'] ?? null,
"start_no_claim" => $row['start_no_claim'] ?? null, "start_no_claim" => $row['start_no_claim'] ?? null,
"end_no_claim" => $row['end_no_claim'] ?? null, "end_no_claim" => $row['end_no_claim'] ?? null,
"plan_id" => $row['plan_id'] ?? null,
"members_effective_date" => $row['member_effective_date'] ?? null, "members_effective_date" => $row['member_effective_date'] ?? null,
"members_expire_date" => $row['member_expiry_date'] ?? null, "members_expire_date" => $row['member_expiry_date'] ?? null,
@@ -575,14 +581,13 @@ class MemberEnrollmentService
"telephone_res" => $row['telephone_res'] ?? null, "telephone_res" => $row['telephone_res'] ?? null,
"telephone_office" => $row['telephone_office'] ?? null, "telephone_office" => $row['telephone_office'] ?? null,
]; ];
// $this->validateRow($row); // $this->validateRow($row);
if (!isset($corporate->currentPolicy) || $corporate->currentPolicy->code != $row['policy_number']) { if (!isset($corporate->currentPolicy) || $corporate->currentPolicy->code != $row['policy_number']) {
throw new ImportRowException(__('enrollment.POLICY_NUMBER_NOT_MATCH', [ throw new ImportRowException(__('enrollment.POLICY_NUMBER_NOT_MATCH', [
'policy_id' => $row['policy_number'] 'policy_id' => $row['policy_number']
]), 0, null, $row); ]), 0, null, $row);
} }
// validasi member efektif date range date in periode date coroporate // validasi member efektif date range date in periode date coroporate
$member_effective_date = date("Y-m-d", strtotime($row['member_effective_date'])); $member_effective_date = date("Y-m-d", strtotime($row['member_effective_date']));
$date_terminated = date("Y-m-d", strtotime($row['date_terminated'])); $date_terminated = date("Y-m-d", strtotime($row['date_terminated']));
@@ -624,6 +629,7 @@ class MemberEnrollmentService
'start' => $corporate->currentPolicy->start 'start' => $corporate->currentPolicy->start
]), 0, null, $row); ]), 0, null, $row);
} }
if ($member_effective_date >= $corporate->currentPolicy->end && ($member_effective_date != $corporate->currentPolicy->end)) { if ($member_effective_date >= $corporate->currentPolicy->end && ($member_effective_date != $corporate->currentPolicy->end)) {
throw new ImportRowException(__('enrollment.LESS_THAN', [ throw new ImportRowException(__('enrollment.LESS_THAN', [
'date_param' => 'Member Effective Date', 'date_param' => 'Member Effective Date',
@@ -632,6 +638,7 @@ class MemberEnrollmentService
'end' => $corporate->currentPolicy->end 'end' => $corporate->currentPolicy->end
]), 0, null, $row); ]), 0, null, $row);
} }
if ($member_effective_date >= $corporate->currentPolicy->end && ($member_effective_date != $corporate->currentPolicy->end)) { if ($member_effective_date >= $corporate->currentPolicy->end && ($member_effective_date != $corporate->currentPolicy->end)) {
throw new ImportRowException(__('enrollment.LESS_THAN', [ throw new ImportRowException(__('enrollment.LESS_THAN', [
'date_param' => 'Member Effective Date', 'date_param' => 'Member Effective Date',
@@ -648,6 +655,7 @@ class MemberEnrollmentService
'start' => $corporate->currentPolicy->start 'start' => $corporate->currentPolicy->start
]), 0, null, $row); ]), 0, null, $row);
} }
if ($members_expire_date >= $corporate->currentPolicy->end && ($members_expire_date != $corporate->currentPolicy->end)) { if ($members_expire_date >= $corporate->currentPolicy->end && ($members_expire_date != $corporate->currentPolicy->end)) {
throw new ImportRowException(__('enrollment.LESS_THAN', [ throw new ImportRowException(__('enrollment.LESS_THAN', [
'date_param' => 'Member Expired Date', 'date_param' => 'Member Expired Date',
@@ -656,6 +664,7 @@ class MemberEnrollmentService
'end' => $corporate->currentPolicy->end 'end' => $corporate->currentPolicy->end
]), 0, null, $row); ]), 0, null, $row);
} }
if ($members_expire_date <= $member_effective_date && ($members_expire_date != $member_effective_date)) { if ($members_expire_date <= $member_effective_date && ($members_expire_date != $member_effective_date)) {
throw new ImportRowException(__('enrollment.MORE_THAN', [ throw new ImportRowException(__('enrollment.MORE_THAN', [
@@ -665,14 +674,14 @@ class MemberEnrollmentService
'start' => $member_effective_date 'start' => $member_effective_date
]), 0, null, $row); ]), 0, null, $row);
} }
if($corporate->code != $row['corporate_id']){ if($corporate->code != $row['corporate_id']){
throw new ImportRowException(__('enrollment.CORPORATE_CODE_NOT_MATCH', [ throw new ImportRowException(__('enrollment.CORPORATE_CODE_NOT_MATCH', [
'corporate_id' => $row['corporate_id'] 'corporate_id' => $row['corporate_id']
]), 0, null, $row); ]), 0, null, $row);
} }
switch ($row['record_mode']) { switch ($row['record_mode']) {
case "1": // New Member case "1": // New Member
$this->validateRow($row); $this->validateRow($row);
@@ -790,12 +799,13 @@ class MemberEnrollmentService
} }
break; break;
case "2": // Member Information Update (Without Replacement Card) case "2": // Member Information Update (Without Replacement Card)
$this->validateRow($row);
// $this->validateRow($row);
$member = Member::query() $member = Member::query()
->where('member_id', $row['member_id']) ->where('member_id', $row['member_id'])
->first(); ->first();
// Validate If Exist Member // // Validate If Exist Member
if (!$member) { if (!$member) {
throw new ImportRowException(__('enrollment.MEMBER_NOT_FOUND', [ throw new ImportRowException(__('enrollment.MEMBER_NOT_FOUND', [
'member_id' => $row['member_id'], 'member_id' => $row['member_id'],
@@ -809,6 +819,102 @@ class MemberEnrollmentService
->with('member') ->with('member')
->first(); ->first();
// Pengecekan jika ada perubahan di plan
$plan = Plan::query()
->where('code', $row['plan_id'])
->first();
if ($plan){
$memberPlan = MemberPlan::query()
->where('member_id', $member->id)
->first();
$memberPlan->plan_id = $plan->id;
$memberPlan->save();
}
// Update jika ada perubahaan di ASO maka akan teriflek ke LMS juga\
$userInsuranceLms = UserInsurance::query()
->where('sNoPolis', $row['member_id'])
->first();
if ($userInsuranceLms){
$userInsuranceLms->sNamaPeserta = $row['name'];
$userInsuranceLms->dStartDate = $row['member_effective_date'];
$userInsuranceLms->dExpireDate = $row['member_expiry_date'];
$nIDUser = $userInsuranceLms->nIDUser;
UserInsurance::updateOrCreate(
['nIDUser' => $nIDUser],
[
'sNamaPeserta' => $row['name'],
'dStartDate' => $row['member_effective_date'],
'dExpireDate' => $row['member_expiry_date'],
'dTanggalLahir' => $row['date_of_birth'],
// 'nNoKTP' => $row['nric'] ?? ,
]
);
/* Lihat ID Marital status di table tm_status_pernikahan Linksehat */
if ($row['relationship_with_principal'] == 'H'){
$sMartialStatus= 6;
$nIDHubunganKeluarga = 3;
} else if ($row['relationship_with_principal'] == 'W'){
$sMartialStatus = 7;
$nIDHubunganKeluarga = 4;
} else if ($row['relationship_with_principal'] == 'S'){
$sMartialStatus = 4;
$nIDHubunganKeluarga = 5;
} else if ($row['relationship_with_principal'] == 'D'){
$sMartialStatus = 5;
$nIDHubunganKeluarga = 5;
} else {
$sMartialStatus = 0;
$nIDHubunganKeluarga = 0;
}
if($row['sex'] == 'M'){
$nIDJenisKelamin = 1;
} else {
$nIDJenisKelamin = 2;
};
// $ip_address = $CI->_prepare_ip($CI->input->ip_address());
$name = explode(" ", $row['name']);
// First name
$first_name = isset($name[0]) ? $name[0] : '';
// Middle name
$middle_name = isset($name[1]) ? $name[1] : '';
// Last name
$last_name = '';
if (count($name) > 2) {
$last_name = implode(" ", array_slice($name, 2));
}
$userLms = User::updateOrCreate(
[
'nID' => $nIDUser // Kondisi untuk mencari data dengan 'nID' yang sesuai dengan $nIDUser
],
[
'sFirstName' => $first_name,
'sLastName' => $middle_name . ' ' .$last_name, // Ubah ini dengan variabel yang sesuai dengan nama belakang (last name)
'sPhone' => $row['telephone_mobile'],
'sEmail' => str_replace(' ', '', $row['email']),
'nIDHubunganKeluarga' => $nIDHubunganKeluarga !== 0 ? $nIDHubunganKeluarga : null,
'dUpdateOn' => date('Y-m-d H:i:s'),
]
);
$userLmsDetail = UserDetail::updateOrCreate(
[
'nIDUser' => $nIDUser
],
[
'nIDUser' => $nIDUser,
'dTanggalLahir' => $row['date_of_birth'],
'dCreateOn' => date('Y-m-d H:i:s'),
'sMartialStatus' => $sMartialStatus != 0 ? $sMartialStatus : null,
'nIDJenisKelamin' => $nIDJenisKelamin,
'sCreateBy' => $nIDUser,
'sKTP' => $row['nric'] ?? null,
]
);
}
if (!$memberPolicy) { if (!$memberPolicy) {
throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [ throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [
'member_id' => $row['member_id'], 'member_id' => $row['member_id'],
@@ -829,7 +935,7 @@ class MemberEnrollmentService
} }
$memberPolicy->member->save(); $memberPolicy->member->save();
$member->save();
// update informasi person // update informasi person
$person = Person::query() $person = Person::query()
->where('id', $member->person_id) ->where('id', $member->person_id)

View File

@@ -2,7 +2,9 @@
namespace App\Http\Middleware; namespace App\Http\Middleware;
use Closure;
use Illuminate\Auth\Middleware\Authenticate as Middleware; use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Support\Facades\Auth;
class Authenticate extends Middleware class Authenticate extends Middleware
{ {
@@ -18,4 +20,13 @@ class Authenticate extends Middleware
return route('login'); return route('login');
} }
} }
public function handle($request, Closure $next, ...$guards)
{
if (Auth::guard('sanctum')->guest()) {
return response()->json(['error' => 'Bearer Authorization is required'], 401);
}
return parent::handle($request, $next, ...$guards);
}
} }

14
app/Models/FilesMcu.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class FilesMcu extends Model
{
use HasFactory;
protected $table = 'files_mcu';
protected $primaryKey = 'id';
protected $fillable = ['memberid', 'original_name', 'path', 'created_by','updated_by', 'created_at', 'updated_at'];
}

View File

@@ -23,6 +23,17 @@ class User extends Model
'full_name', 'full_name',
]; ];
protected $primaryKey = 'nID';
protected $fillable = [
'nID',
'sFirstName',
'sLastName',
'sPhone',
'sEmail',
'nIDHubunganKeluarga',
'dUpdateOn',
];
protected function fullName(): Attribute protected function fullName(): Attribute
{ {
return Attribute::make( return Attribute::make(

View File

@@ -14,7 +14,19 @@ class UserDetail extends Model
const DELETED_AT = 'dDeleteOn'; const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms'; protected $connection = 'oldlms';
protected $primaryKey = 'nID';
protected $table = 'tm_users_detail'; protected $table = 'tm_users_detail';
protected $fillable = [
'nIDUser',
'dTanggalLahir',
'dCreateOn',
'sMartialStatus',
'nIDJenisKelamin',
'sCreateBy',
'sKTP',
];
} }

View File

@@ -15,6 +15,16 @@ class UserInsurance extends Model
const DELETED_AT = 'dDeleteOn'; const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms'; protected $connection = 'oldlms';
protected $primaryKey = 'nIDUser';
protected $table = 'tm_users_insurance'; protected $table = 'tm_users_insurance';
protected $fillable = [
'nIDUser',
'sNamaPeserta',
'dStartDate',
'dExpireDate',
'dTanggalLahir',
'nNoKTP',
'sNoPolis',
];
} }

View File

@@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('files_mcu', function (Blueprint $table) {
$table->increments('id');
$table->bigInteger('memberid');
$table->string('original_name', 255);
$table->string('path', 255);
$table->bigInteger('created_by');
$table->bigInteger('updated_by');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('files_mcu');
}
};

View File

@@ -38,6 +38,7 @@
] ]
}, },
"dependencies": { "dependencies": {
"@ajoelp/json-to-formdata": "^1.5.0",
"@date-io/date-fns": "^2.16.0", "@date-io/date-fns": "^2.16.0",
"@emotion/cache": "^11.10.5", "@emotion/cache": "^11.10.5",
"@emotion/react": "^11.10.5", "@emotion/react": "^11.10.5",

View File

@@ -28,7 +28,9 @@ import {
ButtonGroup, ButtonGroup,
Grid, Grid,
Tooltip, Tooltip,
Divider,
} from '@mui/material'; } from '@mui/material';
import Iconify from '@/components/Iconify';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
import AddIcon from '@mui/icons-material/Add'; import AddIcon from '@mui/icons-material/Add';
@@ -49,8 +51,34 @@ import { enqueueSnackbar } from 'notistack';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
import DialogLog from './sections/DialogLog'; import DialogLog from './sections/DialogLog';
import HistoryIcon from '@mui/icons-material/History'; import HistoryIcon from '@mui/icons-material/History';
import { makeFormData } from '@/utils/jsonToFormData';
export default function CorporatePlanList() { export default function CorporatePlanList({handleSubmitSuccess}) {
// Files MCU
const fileMcuInput = useRef<HTMLInputElement>(null);
const [fileMcus, setFileMcus] = useState([]);
const handleMcuInputChange = (id, member_id) => (event) => {
if (event.target.files[0]) {
const updatedFiles = Array.from(event.target.files).map((file) => ({
file,
id
}));
setFileMcus((prevFileMcus) => {
const newFileMcus = [...prevFileMcus, ...updatedFiles];
submitRequest(id, newFileMcus, member_id);
return newFileMcus;
});
} else {
console.log('Tidak ada file');
}
};
const removeMcuFiles = (id, index) => {
setFileMcus((filesState) =>
filesState.filter((file, fileIndex) => fileIndex !== index || file.id !== id)
);
};
const [submitLoading, setSubmitLoading] = useState(false);
const { themeStretch } = useSettings(); const { themeStretch } = useSettings();
const { corporate_id } = useParams(); const { corporate_id } = useParams();
const [searchParams, setSearchParams] = useSearchParams(); const [searchParams, setSearchParams] = useSearchParams();
@@ -149,6 +177,47 @@ export default function CorporatePlanList() {
</form> </form>
); );
} }
function submitRequest(id, newFileMcus, member_id) {
setSubmitLoading(true);
if (newFileMcus && newFileMcus.length > 0) {
const fileWithId = newFileMcus.find((file) => file.id === id);
if (fileWithId) {
const formData = makeFormData({
id: id,
memberid: member_id,
result_files: fileWithId.file,
});
axios
.post('/files-mcu', formData)
.then((response) => {
const responseData = response?.data;
if(responseData)
{
setTimeout(() => {
loadDataTableData();
}, 2000);
enqueueSnackbar(responseData.message ?? 'Berhasil tambah file MemberID '+member_id+', silahkan lihat dilaporan', { variant: 'success' });
handleSubmitSuccess();
}
})
.catch(({ response }) => {
const responseData = response?.data;
if(responseData)
{
enqueueSnackbar(responseData.message ?? 'Something Went Wrong', { variant: 'error' });
}
})
.then(() => {
setSubmitLoading(false);
});
} else {
console.log(`File dengan ID ${id} tidak ditemukan`);
}
}
}
// End Files MCU
function ImportForm(props: any) { function ImportForm(props: any) {
// IMPORT // IMPORT
@@ -178,9 +247,7 @@ export default function CorporatePlanList() {
const handleMemberList = async (appliedFilter = null) => { const handleMemberList = async (appliedFilter = null) => {
axios.get('corporates/' + corporate_id + '/members/list').then((response) => { axios.get('corporates/' + corporate_id + '/members/list').then((response) => {
console.log(response);
const link = document.createElement('a'); const link = document.createElement('a');
console.log(response.data.data.file_name);
link.href = response.data.data.file_url; link.href = response.data.data.file_url;
link.setAttribute('download', response.data.data.file_name); link.setAttribute('download', response.data.data.file_name);
document.body.appendChild(link); document.body.appendChild(link);
@@ -577,21 +644,81 @@ export default function CorporatePlanList() {
</Grid> </Grid>
</Grid> </Grid>
</Grid> </Grid>
<Typography sx={{ fontWeight: '600', mb: 1 }}>File History</Typography>
<Grid container sx={{ pb: 2, mb: 2, borderBottom: 1 }}>
<Grid item xs={12}>
<Grid container>
<Grid item xs={12}>
{row.file_mcu_names
? row.file_mcu_names.split(',').map((fileName, index) => (
<div key={index}>{fileName}</div>
))
: '-'}
</Grid>
</Grid>
</Grid>
</Grid>
<Grid> <Grid spacing={1}>
<LoadingButton <Stack sx={{ marginTop: 1}}>
id="upload-button" <LoadingButton
variant="outlined" id="upload-button"
startIcon={<InsertDriveFileIcon />} variant="outlined"
// sx={{ p: 1.8 }} startIcon={<InsertDriveFileIcon />}
// onClick={() => {handleDownloadLog(row)}} // sx={{ p: 1.8 }}
onClick={() => { // onClick={() => {handleDownloadLog(row)}}
setDialogLogOpen(true); onClick={() => {
}} setDialogLogOpen(true);
loading={loadingLog} }}
> loading={loadingLog}
Download LOG >
</LoadingButton> Download LOG
</LoadingButton>
</Stack>
{/* -------------------------------Upload Dokumen MCU------------------------------- */}
<Stack sx={{ marginTop: 1}}>
{/*<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2}}
>
{fileMcus &&
fileMcus
.filter((datas) => datas.id === row.id)
.map((datas, index) => (
<Stack direction="row" justifyContent={'space-between'} key={index}>
<Typography sx={{ color: "text.secondary" }}>{datas.file.name}</Typography>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
removeMcuFiles(datas.id, index);
}}
sx={{ cursor: 'pointer' }}
></Iconify>
</Stack>
))}
</Stack>*/}
<input
type="file"
id={`file-${row.id}`}
ref={fileMcuInput}
style={{ display: 'none' }}
onChange={(event) => {
handleMcuInputChange(row.id, row.member_id)(event);
}}
accept="application/pdf"
/>
<LoadingButton
variant="outlined"
onClick={() => {
fileMcuInput.current.click();
}}
>
<Iconify icon="eva:plus-fill" />
Add Result
</LoadingButton>
</Stack>
</Grid> </Grid>
<DialogLog <DialogLog

View File

@@ -0,0 +1,6 @@
import jsonToFormData from '@ajoelp/json-to-formdata';
export function makeFormData(object: any) {
return jsonToFormData(object)
}

View File

@@ -1,4 +1,4 @@
REACT_APP_HOST_API_URL="http://localhost:8000" REACT_APP_HOST_API_URL="http://localhost:8000"
VITE_API_URL="http://localhost:8000/api/hospitalportal" VITE_API_URL="http://localhost:8000/api/v1/hospitalportal"

View File

@@ -1 +1 @@
VITE_API_URL="https://aso-api.linksehat.dev/api/hospitalportal" VITE_API_URL="https://aso-api.linksehat.dev/api/v1/hospitalportal"

View File

@@ -0,0 +1,18 @@
<svg height="20" viewBox="0 0 28 20" width="28" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs><rect id="a" height="20" rx="3" width="28"/>
<mask id="b" fill="#fff">
<use fill="#fff" fill-rule="evenodd" xlink:href="#a"/>
</mask>
</defs>
<g fill="none" fill-rule="evenodd">
<use fill="#0a17a7" xlink:href="#a"/>
<path d="m29.2824692-1.91644623 1.4911811 2.21076686-9.4483006 6.37223314 6.6746503.0001129v6.66666663l-6.6746503-.0007795 9.4483006 6.3731256-1.4911811 2.2107668-11.9501195-8.0608924.0009836 7.4777795h-6.6666666l-.000317-7.4777795-11.9488189 8.0608924-1.49118107-2.2107668 9.448-6.3731256-6.67434973.0007795v-6.66666663l6.67434973-.0001129-9.448-6.37223314 1.49118107-2.21076686 11.9488189 8.06.000317-7.4768871h6.6666666l-.0009836 7.4768871z" fill="#fff" mask="url(#b)"/>
<g stroke="#db1f35" stroke-linecap="round" stroke-width=".667">
<path d="m18.668 6.332 12.665-8.332" mask="url(#b)"/>
<path d="m20.013 21.35 11.354-7.652" mask="url(#b)" transform="matrix(1 0 0 -1 0 35.048)"/>
<path d="m8.006 6.31-11.843-7.981" mask="url(#b)"/>
<path d="m9.29 22.31-13.127-8.705" mask="url(#b)" transform="matrix(1 0 0 -1 0 35.915)"/>
</g>
<path d="m0 12h12v8h4v-8h12v-4h-12v-8h-4v8h-12z" fill="#e6273e" mask="url(#b)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,9 @@
<svg height="20" viewBox="0 0 28 20" width="28" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<rect id="a" height="10" rx="0" width="28"/>
</defs>
<g fill="none" fill-rule="evenodd">
<use fill="#D82028" xlink:href="#a"/>
<use fill="#FFF" xlink:href="#a" y="10"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 334 B

View File

@@ -0,0 +1,15 @@
{
"greeting": "Hello",
"buttonText": "Click Me",
"infoLogin": "Enter the registered account",
"txtLogin1" : "Sign in to Hospital Portal",
"txtLogin2" : "Enter your details below",
"txtCardSearchMember1" : "Guarantee Submission",
"txtCardSearchMember2" : "Find Member",
"txtCardSearchMember3" : "Date Birth",
"txtCardSearchMember4" : "Member ID",
"txtCardSearchMember5" : "Member",
"txtDialogMember1" : "Benefit Summary",
"txtDialogMember2" : "Request LOG",
"txtDialogMember3" : "Member Detail"
}

View File

@@ -0,0 +1,18 @@
<svg height="20" viewBox="0 0 28 20" width="28" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs><rect id="a" height="20" rx="3" width="28"/>
<mask id="b" fill="#fff">
<use fill="#fff" fill-rule="evenodd" xlink:href="#a"/>
</mask>
</defs>
<g fill="none" fill-rule="evenodd">
<use fill="#0a17a7" xlink:href="#a"/>
<path d="m29.2824692-1.91644623 1.4911811 2.21076686-9.4483006 6.37223314 6.6746503.0001129v6.66666663l-6.6746503-.0007795 9.4483006 6.3731256-1.4911811 2.2107668-11.9501195-8.0608924.0009836 7.4777795h-6.6666666l-.000317-7.4777795-11.9488189 8.0608924-1.49118107-2.2107668 9.448-6.3731256-6.67434973.0007795v-6.66666663l6.67434973-.0001129-9.448-6.37223314 1.49118107-2.21076686 11.9488189 8.06.000317-7.4768871h6.6666666l-.0009836 7.4768871z" fill="#fff" mask="url(#b)"/>
<g stroke="#db1f35" stroke-linecap="round" stroke-width=".667">
<path d="m18.668 6.332 12.665-8.332" mask="url(#b)"/>
<path d="m20.013 21.35 11.354-7.652" mask="url(#b)" transform="matrix(1 0 0 -1 0 35.048)"/>
<path d="m8.006 6.31-11.843-7.981" mask="url(#b)"/>
<path d="m9.29 22.31-13.127-8.705" mask="url(#b)" transform="matrix(1 0 0 -1 0 35.915)"/>
</g>
<path d="m0 12h12v8h4v-8h12v-4h-12v-8h-4v8h-12z" fill="#e6273e" mask="url(#b)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,9 @@
<svg height="20" viewBox="0 0 28 20" width="28" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<rect id="a" height="10" rx="0" width="28"/>
</defs>
<g fill="none" fill-rule="evenodd">
<use fill="#D82028" xlink:href="#a"/>
<use fill="#FFF" xlink:href="#a" y="10"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 334 B

View File

@@ -0,0 +1,15 @@
{
"greeting": "Halo",
"buttonText": "Klik Saya",
"infoLogin": "Masukan akun yang telah terdaftar",
"txtLogin1" : "Masuk ke Hospital Portal",
"txtLogin2" : "Masukkan detail Anda di bawah ini",
"txtCardSearchMember1" : "Pengajuan Jaminan",
"txtCardSearchMember2" : "Cari Anggota",
"txtCardSearchMember3" : "Tanggal Lahir",
"txtCardSearchMember4" : "Member ID",
"txtCardSearchMember5" : "Member",
"txtDialogMember1" : "Ringkasan Manfaat",
"txtDialogMember2" : "Request LOG",
"txtDialogMember3" : "Detail Member"
}

View File

@@ -0,0 +1,15 @@
{
"greeting": "Hello",
"buttonText": "Click Me",
"infoLogin": "Enter the registered account",
"txtLogin1" : "Sign in to Hospital Portal",
"txtLogin2" : "Enter your details below",
"txtCardSearchMember1" : "Guarantee Submission",
"txtCardSearchMember2" : "Find Member",
"txtCardSearchMember3" : "Date Birth",
"txtCardSearchMember4" : "Member ID",
"txtCardSearchMember5" : "Member",
"txtDialogMember1" : "Benefit Summary",
"txtDialogMember2" : "Request LOG",
"txtDialogMember3" : "Member Detail"
}

View File

@@ -0,0 +1,15 @@
{
"greeting": "Halo",
"buttonText": "Klik Saya",
"infoLogin": "Masukan akun yang telah terdaftar",
"txtLogin1" : "Masuk ke Hospital Portal",
"txtLogin2" : "Masukkan detail Anda di bawah ini",
"txtCardSearchMember1" : "Pengajuan Jaminan",
"txtCardSearchMember2" : "Cari Anggota",
"txtCardSearchMember3" : "Tanggal Lahir",
"txtCardSearchMember4" : "Member ID",
"txtCardSearchMember5" : "Member",
"txtDialogMember1" : "Ringkasan Manfaat",
"txtDialogMember2" : "Request LOG",
"txtDialogMember3" : "Detail Member"
}

View File

@@ -0,0 +1,9 @@
<svg height="20" viewBox="0 0 28 20" width="28" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<rect id="a" height="10" rx="0" width="28"/>
</defs>
<g fill="none" fill-rule="evenodd">
<use fill="#D82028" xlink:href="#a"/>
<use fill="#FFF" xlink:href="#a" y="10"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 334 B

View File

@@ -0,0 +1,7 @@
const getLocalizedData = async (locale) => {
const response = await fetch(`../public/image/${locale}.json`); // Mengambil file lokal berdasarkan bahasa yang dipilih
const data = await response.json();
return data;
};
export default getLocalizedData;

View File

@@ -17,7 +17,7 @@ export default function Logo({ disabledLink = false, sx }: Props) {
const logo = ( const logo = (
<Box sx={{ width: 40, height: 40, ...sx }}> <Box sx={{ width: 40, height: 40, ...sx }}>
<img src="/logo/logo-linksehat.png" alt="LinkSehat" /> <img src="/logo/logo_single.svg" alt="LinkSehat" />
</Box> </Box>
); );

View File

@@ -0,0 +1,38 @@
import React, { createContext, useState, useEffect, useRef } from 'react';
import getLocalizedData from '../LocalizationUtil';
export const LanguageContext = createContext();
export const LanguageProvider = ({ children }) => {
const [currentLocale, setCurrentLocale] = useState(localStorage.getItem('currentLocale') ? localStorage.getItem('currentLocale') : 'id-ID');
const [localeData, setLocaleData] = useState('id');
const cancelToken = useRef(null);
useEffect(() => {
const fetchData = async () => {
const token = { cancelled: false };
cancelToken.current = token;
try {
const data = await getLocalizedData(currentLocale);
if (!cancelToken.current.cancelled) {
setLocaleData(data);
}
} catch (error) {
console.error('Error fetching localized data:', error);
// Tangani kesalahan jika diperlukan
}
};
fetchData();
return () => {
cancelToken.current.cancelled = true;
};
}, [currentLocale]);
return (
<LanguageContext.Provider value={{ currentLocale, setCurrentLocale, localeData }}>
{children}
</LanguageContext.Provider>
);
};

View File

@@ -122,10 +122,18 @@ function AuthProvider({ children }: AuthProviderProps) {
initialize(); initialize();
}, []); }, []);
const headers = {
headers: {
'Accept': 'application/json',
'Content-Type' : 'application/json',
'Accept-Language': (localStorage.getItem('currentLocale') ? localStorage.getItem('currentLocale') : 'id-ID'),
},
};
const login = async (email: string, password: string) => axios const login = async (email: string, password: string) => axios
.post('/login', { email, password }) .post('/login', { email, password }, headers)
.then((response) => { .then((response) => {
const { user, token } = response.data; const { user, token } = response.data.data;
setSession(token); setSession(token);
dispatch({ dispatch({

View File

@@ -12,6 +12,7 @@ import { HelmetProvider } from 'react-helmet-async';
// contexts // contexts
import { SettingsProvider } from './contexts/SettingsContext'; import { SettingsProvider } from './contexts/SettingsContext';
import { CollapseDrawerProvider } from './contexts/CollapseDrawerContext'; import { CollapseDrawerProvider } from './contexts/CollapseDrawerContext';
import { LanguageProvider } from './contexts/LanguageContext';
// //
import App from './App'; import App from './App';
@@ -23,7 +24,9 @@ ReactDOM.render(
<SettingsProvider> <SettingsProvider>
<CollapseDrawerProvider> <CollapseDrawerProvider>
<BrowserRouter> <BrowserRouter>
<App /> <LanguageProvider>
<App />
</LanguageProvider>
</BrowserRouter> </BrowserRouter>
</CollapseDrawerProvider> </CollapseDrawerProvider>
</SettingsProvider> </SettingsProvider>

View File

@@ -1,28 +1,24 @@
import { useState } from 'react'; import React, { useState, useContext } from 'react';
// @mui // @mui
import { MenuItem, Stack } from '@mui/material'; import { ButtonBase, Box, Typography, MenuItem, Stack } from '@mui/material';
// components // components
import Image from '@/components/Image'; import Image from '@/components/Image';
import MenuPopover from '@/components/MenuPopover'; import MenuPopover from '@/components/MenuPopover';
import { IconButtonAnimate } from '@/components/animate'; import { IconButtonAnimate } from '@/components/animate';
import { LanguageContext } from '@/contexts/LanguageContext';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
const LANGS = [ const LANGS = [
{
label: 'Bahasa Indonesia',
value: 'id-ID',
icon: '/image/ic_flag_id.svg',
},
{ {
label: 'English', label: 'English',
value: 'en', value: 'en-US',
icon: 'https://minimal-assets-api.vercel.app/assets/icons/ic_flag_en.svg', icon: '/image/ic_flag_en.svg',
},
{
label: 'German',
value: 'de',
icon: 'https://minimal-assets-api.vercel.app/assets/icons/ic_flag_de.svg',
},
{
label: 'French',
value: 'fr',
icon: 'https://minimal-assets-api.vercel.app/assets/icons/ic_flag_fr.svg',
}, },
]; ];
@@ -39,18 +35,50 @@ export default function LanguagePopover() {
setOpen(null); setOpen(null);
}; };
const { setCurrentLocale } = useContext(LanguageContext);
const handleChangeLanguage = (language) => {
localStorage.setItem('currentLocale', language);
setCurrentLocale(language);
};
return ( return (
<> <>
<IconButtonAnimate <Box display="flex" alignItems="center" border={0} borderColor="grey.300" borderRadius={3} p={1}>
onClick={handleOpen}
sx={{ <IconButtonAnimate
width: 40, onClick={handleOpen}
height: 40, sx={{
...(open && { bgcolor: 'action.selected' }), width: 35,
}} height: 35,
> ...(open && { bgcolor: 'action.selected' }),
<Image disabledEffect src={LANGS[0].icon} alt={LANGS[0].label} /> }}
</IconButtonAnimate> >
<Image
disabledEffect
src={(
!localStorage.getItem('currentLocale')
? LANGS[0].icon
: localStorage.getItem('currentLocale') === 'id-ID'
? LANGS[0].icon
: LANGS[1].icon
)}
alt={
!localStorage.getItem('currentLocale')
? LANGS[0].label
: localStorage.getItem('currentLocale') === 'id-ID'
? LANGS[0].label
: LANGS[1].label
}
/>
</IconButtonAnimate>
<ButtonBase onClick={handleOpen}>
<Typography variant="body2" component="span" marginRight={1} color="textPrimary">
Language
</Typography>
</ButtonBase>
</Box>
<MenuPopover <MenuPopover
open={Boolean(open)} open={Boolean(open)}
@@ -67,17 +95,22 @@ export default function LanguagePopover() {
{LANGS.map((option) => ( {LANGS.map((option) => (
<MenuItem <MenuItem
key={option.value} key={option.value}
selected={option.value === LANGS[0].value} selected={option.value === localStorage.getItem('currentLocale')}
onClick={handleClose} onClick = {() => {
handleClose();
handleChangeLanguage(option.value);
}}
> >
<Image <Image
disabledEffect disabledEffect
alt={option.label} alt={option.label}
src={option.icon} src={option.icon}
sx={{ width: 28, mr: 2 }} sx={{ width: 28 }}
/> />
<Typography variant="body2" component="span" marginLeft={1} color="textPrimary">
{option.label} {option.label}
</Typography>
</MenuItem> </MenuItem>
))} ))}
</Stack> </Stack>

View File

@@ -93,8 +93,8 @@ export default function DashboardHeader({
<Stack direction="row" alignItems="center" spacing={{ xs: 0.5, sm: 1.5 }}> <Stack direction="row" alignItems="center" spacing={{ xs: 0.5, sm: 1.5 }}>
<LanguagePopover /> <LanguagePopover />
<NotificationsPopover /> {/*<NotificationsPopover />
<ContactsPopover /> <ContactsPopover />*/}
<AccountPopover /> <AccountPopover />
</Stack> </Stack>
</Toolbar> </Toolbar>

View File

@@ -20,12 +20,12 @@ import DialogDetailClaim from '@/components/dialogs/DialogDetailClaim';
// const [notifications, setNotifications] = useState([]) // const [notifications, setNotifications] = useState([])
// const itemList = [ 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: '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: '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: '10:00 WIB' },
// // { info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '11:00 WIB' }, { info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '11:00 WIB' },
// ]; ];
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@@ -66,7 +66,7 @@ export default function Dashboard() {
const [policyData, setPolicyData] = useState<PolicyProps>(defaultPolicyData); const [policyData, setPolicyData] = useState<PolicyProps>(defaultPolicyData);
// TODO Remove This // TODO Remove This
const [itemList, setItemList] = useState([]); //const [itemList, setItemList] = useState([]);
function handleDataLoaded(dataTable) { function handleDataLoaded(dataTable) {
let dummyData = []; let dummyData = [];
dataTable.map(function(data) { dataTable.map(function(data) {
@@ -79,7 +79,7 @@ export default function Dashboard() {
} }
}) })
setItemList(dummyData); //setItemList(dummyData);
} }
return ( return (

View File

@@ -1,3 +1,4 @@
import React, { useContext, useRef, useState, useEffect } from 'react';
import { capitalCase } from "change-case"; import { capitalCase } from "change-case";
import { Link as RouterLink } from "react-router-dom"; import { Link as RouterLink } from "react-router-dom";
// @mui // @mui
@@ -23,6 +24,7 @@ import Logo from "@/components/Logo";
import Image from "@/components/Image"; import Image from "@/components/Image";
// sections // sections
import { LoginForm } from "@/sections/auth/login"; import { LoginForm } from "@/sections/auth/login";
import { LanguageContext } from '@/contexts/LanguageContext';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@@ -70,6 +72,7 @@ const ContentStyle = styled("div")(({ theme }) => ({
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
export default function Login() { export default function Login() {
const { localeData } = useContext(LanguageContext);
const { method } = useAuth(); const { method } = useAuth();
const smUp = useResponsive("up", "sm"); const smUp = useResponsive("up", "sm");
@@ -80,7 +83,7 @@ export default function Login() {
<Page title="Login"> <Page title="Login">
<RootStyle> <RootStyle>
<HeaderStyle> <HeaderStyle>
<Logo sx={{ width: 150, height: 150 }} /> {/*<Logo sx={{ width: 150, height: 150 }} />
{smUp && ( {smUp && (
<Typography variant="body2" sx={{ mt: { md: -2 } }}> <Typography variant="body2" sx={{ mt: { md: -2 } }}>
Has problem with your account? {""} Has problem with your account? {""}
@@ -97,7 +100,7 @@ export default function Login() {
Contact Us Contact Us
</Link> </Link>
</Typography> </Typography>
)} )}*/}
</HeaderStyle> </HeaderStyle>
{/* {mdUp && ( {/* {mdUp && (
@@ -121,16 +124,17 @@ export default function Login() {
alignItems="center" alignItems="center"
sx={{ mb: 5 }} sx={{ mb: 5 }}
> >
<Logo sx={{ width: 90, height: 90 }} />
<Box sx={{ flexGrow: 1 }}> <Box sx={{ flexGrow: 1 }}>
<Typography variant="h4" gutterBottom> <Typography variant="h4" gutterBottom>
Sign in to LinkSehat {localeData.txtLogin1}
</Typography> </Typography>
<Typography sx={{ color: "text.secondary" }}> <Typography variant="body1" sx={{ color: 'text.secondary' }}>
Enter your details below. {localeData.txtLogin2}
</Typography> </Typography>
</Box> </Box>
<Tooltip {/*<Tooltip
title={capitalCase(method)} title={capitalCase(method)}
placement="right" placement="right"
> >
@@ -141,12 +145,12 @@ export default function Login() {
sx={{ width: 32, height: 32 }} sx={{ width: 32, height: 32 }}
/> />
</> </>
</Tooltip> </Tooltip>*/}
</Stack> </Stack>
<LoginForm /> <LoginForm />
{false && !smUp && ( {/*{false && !smUp && (
<Typography <Typography
variant="body2" variant="body2"
align="center" align="center"
@@ -161,7 +165,7 @@ export default function Login() {
Get started Get started
</Link> </Link>
</Typography> </Typography>
)} )}*/}
</ContentStyle> </ContentStyle>
</Container> </Container>
</RootStyle> </RootStyle>

View File

@@ -1,5 +1,5 @@
import * as Yup from 'yup'; import * as Yup from 'yup';
import { useState } from 'react'; import React, { useContext, useRef, useState, useEffect } from 'react';
import { Link as RouterLink, useNavigate } from 'react-router-dom'; import { Link as RouterLink, useNavigate } from 'react-router-dom';
// form // form
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
@@ -15,6 +15,7 @@ import useIsMountedRef from '@/hooks/useIsMountedRef';
// components // components
import Iconify from '@/components/Iconify'; import Iconify from '@/components/Iconify';
import { FormProvider, RHFTextField, RHFCheckbox } from '@/components/hook-form'; import { FormProvider, RHFTextField, RHFCheckbox } from '@/components/hook-form';
import { LanguageContext } from '@/contexts/LanguageContext';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@@ -26,6 +27,7 @@ type FormValuesProps = {
}; };
export default function LoginForm() { export default function LoginForm() {
const { localeData } = useContext(LanguageContext);
const { login } = useAuth(); const { login } = useAuth();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -34,8 +36,8 @@ export default function LoginForm() {
const [showPassword, setShowPassword] = useState(false); const [showPassword, setShowPassword] = useState(false);
const LoginSchema = Yup.object().shape({ const LoginSchema = Yup.object().shape({
email: Yup.string().email('Email must be a valid email address').required('Email is required'), email: Yup.string().email('Format email tidak valid').required('Email harus diisi'),
password: Yup.string().required('Password is required'), password: Yup.string().required('Password harus diisi'),
}); });
const defaultValues = { const defaultValues = {
@@ -75,10 +77,10 @@ export default function LoginForm() {
return ( return (
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}> <FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
<Stack spacing={3}> <Stack spacing={3}>
<Alert severity="info">Email : admin@linksehat.dev & Password : password</Alert> <Alert severity="info">{localeData.infoLogin}</Alert>
{!!errors.afterSubmit && <Alert severity="error">{errors.afterSubmit.message}</Alert>} {!!errors.afterSubmit && <Alert severity="error">{errors.afterSubmit.data.meta.message}</Alert>}
<RHFTextField name="email" label="Email address" /> <RHFTextField name="email" label="Email" required/>
<RHFTextField <RHFTextField
name="password" name="password"
@@ -93,14 +95,15 @@ export default function LoginForm() {
</InputAdornment> </InputAdornment>
), ),
}} }}
required
/> />
</Stack> </Stack>
<Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ my: 2 }}> <Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ my: 2 }}>
<RHFCheckbox name="remember" label="Remember me" /> {/*<RHFCheckbox name="remember" label="Remember me" />
<Link component={RouterLink} variant="subtitle2" to={PATH_AUTH.resetPassword}> <Link component={RouterLink} variant="subtitle2" to={PATH_AUTH.resetPassword}>
Forgot password? Forgot password?
</Link> </Link>*/}
</Stack> </Stack>
<LoadingButton <LoadingButton
@@ -109,6 +112,7 @@ export default function LoginForm() {
type="submit" type="submit"
variant="contained" variant="contained"
loading={isSubmitting} loading={isSubmitting}
sx={{ marginTop: 2 }}
> >
Login Login
</LoadingButton> </LoadingButton>

View File

@@ -13,7 +13,7 @@ import {
} from '@mui/material'; } from '@mui/material';
import { ChevronRight } from '@mui/icons-material'; import { ChevronRight } from '@mui/icons-material';
// React // React
import React, { useState } from 'react'; import React, { useContext, useState } from 'react';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
import Iconify from '@/components/Iconify'; import Iconify from '@/components/Iconify';
import { DatePicker, LocalizationProvider, MobileDatePicker } from '@mui/x-date-pickers'; import { DatePicker, LocalizationProvider, MobileDatePicker } from '@mui/x-date-pickers';
@@ -25,6 +25,7 @@ import MuiDialog from '@/components/MuiDialog';
import axios from '@/utils/axios'; import axios from '@/utils/axios';
import { useSnackbar } from 'notistack'; import { useSnackbar } from 'notistack';
import DialogMember from './DialogMember'; import DialogMember from './DialogMember';
import { LanguageContext } from '@/contexts/LanguageContext';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@@ -46,29 +47,32 @@ const ItemNotificationStyle = styled(Card)(({ theme }) => ({
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
export default function CardSearchMember(handleSubmitSuccess) { export default function CardSearchMember(handleSubmitSuccess) {
const { localeData } = useContext(LanguageContext);
const {enqueueSnackbar} = useSnackbar(); const {enqueueSnackbar} = useSnackbar();
const [noPolis, setNoPolis] = useState('AW001-01'); const [noPolis, setNoPolis] = useState('AW001-01');
const [tanggalLahir, setTanggalLahir] = useState('1991-01-10'); const [birthDate, setBirthDate] = useState('1991-01-10');
const [loadingBenefit, setLoadingBenefit] = useState(false); const [loadingBenefit, setLoadingBenefit] = useState(false);
const [loadingClaim, setLoadingClaim] = useState(false); const [loadingClaim, setLoadingClaim] = useState(false);
const [openDialogBenefit, setOpenDialogBenefit] = useState(false); const [openDialogBenefit, setOpenDialogBenefit] = useState(false);
const [openDialogClaim, setOpenDialogClaim] = useState(false); const [openDialogClaim, setOpenDialogClaim] = useState(false);
const [currentMember, setCurrentMember] = useState(null); const [currentMember, setCurrentMember] = useState(null);
const [nameMember, setNameMember] = useState('');
function handleSearchMember() { function handleSearchMember() {
setLoadingBenefit(true) setLoadingBenefit(true)
axios.post('/search-member', { axios.post('/search-member', {
no_polis: noPolis, no_polis: noPolis,
birth_date: tanggalLahir ? fPostFormat(tanggalLahir, 'yyyy-MM-dd') : null birth_date: birthDate ? fPostFormat(birthDate, 'yyyy-MM-dd') : null
}) })
.then((response) => { .then((response) => {
setOpenDialogBenefit(true) setOpenDialogBenefit(true)
setCurrentMember(response.data.data) setCurrentMember(response.data.data)
setNameMember(response.data.data.name);
}) })
.catch(({response}) => { .catch(({response}) => {
enqueueSnackbar(response.data.errors ? response.data.errors[0] : (response.data ? response.data.message : 'Opps, Something went Wrong!'), {variant : "error"}) enqueueSnackbar(response.data.errors ? response.data.errors[0] : (response.data ? response.data.meta.message : 'Opps, Something went Wrong!'), {variant : "error"})
}) })
.then(() => { .then(() => {
setLoadingBenefit(false) setLoadingBenefit(false)
@@ -90,23 +94,23 @@ export default function CardSearchMember(handleSubmitSuccess) {
component="span" component="span"
sx={{ display: 'flex', alignItems: 'center' }} sx={{ display: 'flex', alignItems: 'center' }}
> >
Pengajuan Jaminan {localeData.txtCardSearchMember1}
</Typography> </Typography>
</Typography> </Typography>
</Stack> </Stack>
<Stack gap={2}> <Stack gap={2}>
<TextField variant="outlined" label="Member ID" value={noPolis} onChange={(event) => { <TextField variant="outlined" label={localeData.txtCardSearchMember4} value={noPolis} onChange={(event) => {
setNoPolis(event.target.value) setNoPolis(event.target.value)
}}></TextField> }} required></TextField>
<LocalizationProvider dateAdapter={AdapterDateFns}> <LocalizationProvider dateAdapter={AdapterDateFns}>
<DatePicker <DatePicker
label="Tanggal Lahir" label={localeData.txtCardSearchMember3}
value={tanggalLahir} value={birthDate}
onChange={(newValue) => { onChange={(newValue) => {
setTanggalLahir( (newValue)); setTanggalLahir( (newValue));
}} }}
inputFormat="dd-MM-yyyy" inputFormat="dd-MM-yyyy"
renderInput={(params) => <TextField {...params} />} renderInput={(params) => <TextField {...params} required/>}
/> />
</LocalizationProvider> </LocalizationProvider>
@@ -124,7 +128,7 @@ export default function CardSearchMember(handleSubmitSuccess) {
}} }}
> >
<Iconify icon="eva:eye-fill" marginRight={0.75} /> <Iconify icon="eva:eye-fill" marginRight={0.75} />
Cari Member {localeData.txtCardSearchMember2}
</LoadingButton> </LoadingButton>
{/* <LoadingButton {/* <LoadingButton
variant="contained" variant="contained"
@@ -142,7 +146,7 @@ export default function CardSearchMember(handleSubmitSuccess) {
{/* {/*
<DialogBenefit open={openDialogBenefit} setOpen={setOpenDialogBenefit}></DialogBenefit> */} <DialogBenefit open={openDialogBenefit} setOpen={setOpenDialogBenefit}></DialogBenefit> */}
<MuiDialog <MuiDialog
title={{name: "Member"}} title={{name: nameMember}}
openDialog={openDialogBenefit} openDialog={openDialogBenefit}
setOpenDialog={setOpenDialogBenefit} setOpenDialog={setOpenDialogBenefit}
content={DialogMember(currentMember, () => {setOpenDialogBenefit(false); handleSubmitSuccess()})} content={DialogMember(currentMember, () => {setOpenDialogBenefit(false); handleSubmitSuccess()})}

View File

@@ -4,20 +4,22 @@ import { LoadingButton, TabPanel } from "@mui/lab";
import { Button, Card, Divider, Grid, LinearProgress, linearProgressClasses, Typography } from "@mui/material"; import { Button, Card, Divider, Grid, LinearProgress, linearProgressClasses, Typography } from "@mui/material";
import { Tab, Tabs } from "@mui/material"; import { Tab, Tabs } from "@mui/material";
import { Box, Stack } from "@mui/material"; import { Box, Stack } from "@mui/material";
import { useEffect, useState } from "react"; import React, { useEffect, useState, useContext } from "react";
import { fCurrency } from '@/utils/formatNumber'; import { fCurrency } from '@/utils/formatNumber';
import { fPostFormat } from '@/utils/formatTime'; import { fPostFormat } from '@/utils/formatTime';
import { Avatar } from '@mui/material'; import { Avatar } from '@mui/material';
import Iconify from '@/components/Iconify'; import Iconify from '@/components/Iconify';
import FormRequestClaim from './FormRequestClaim'; import FormRequestClaim from './FormRequestClaim';
import { LanguageContext } from '@/contexts/LanguageContext';
export default function DialogMember(member, handleSubmitSuccess) { export default function DialogMember(member, handleSubmitSuccess) {
const { localeData } = useContext(LanguageContext);
const [currentTab, setCurrentTab] = useState('request') const [currentTab, setCurrentTab] = useState('request')
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
useEffect(() => { useEffect(() => {
setCurrentTab('benefit') setCurrentTab('detail')
}, [member]) }, [member])
function handleChangeTab(event: React.SyntheticEvent, newValue: string) { function handleChangeTab(event: React.SyntheticEvent, newValue: string) {
@@ -67,13 +69,93 @@ export default function DialogMember(member, handleSubmitSuccess) {
onChange={handleChangeTab} onChange={handleChangeTab}
aria-label="wrapped label tabs example" aria-label="wrapped label tabs example"
> >
<Tab <Tab value="detail" label={localeData.txtDialogMember3} />
value="benefit" <Tab value="benefit" label={localeData.txtDialogMember1} />
label="Benefit Summary" <Tab value="request" label={localeData.txtDialogMember2} />
/>
<Tab value="request" label="Request Penjaminan" />
</Tabs> </Tabs>
<TabPanel value={currentTab} index={'detail'}>
<Stack spacing={2}>
<Grid container sx={{ pb: 2, mb: 2, borderBottom: 0 }}>
<Grid item xs={6}>
<Grid container>
<Grid item xs={6}>
Mapping ID
</Grid>
<Grid item xs={6}>
: {1 ?? '-'}
</Grid>
<Grid item xs={6}>
Policy Number
</Grid>
<Grid item xs={6}>
: {1 ?? '-'}
</Grid>
<Grid item xs={6}>
NRIC
</Grid>
<Grid item xs={6}>
: {1 ?? '-'}
</Grid>
<Grid item xs={6}>
NIK
</Grid>
<Grid item xs={6}>
: {1 ?? '-'}
</Grid>
<Grid item xs={6}>
Email
</Grid>
<Grid item xs={6}>
: {1 ?? '-'}
</Grid>
</Grid>
</Grid>
<Grid item xs={6}>
<Grid container>
<Grid item xs={6}>
Birth Date
</Grid>
<Grid item xs={6}>
: {1 ?? '-'}
</Grid>
<Grid item xs={6}>
Gender
</Grid>
<Grid item xs={6}>
: {1 ?? '-'}
</Grid>
<Grid item xs={6}>
Marital Status
</Grid>
<Grid item xs={6}>
: {1 ?? '-'}
</Grid>
<Grid item xs={6}>
Language
</Grid>
<Grid item xs={6}>
: {1 ?? '-'}
</Grid>
<Grid item xs={6}>
Race
</Grid>
<Grid item xs={6}>
: {1 ?? '-'}
</Grid>
<Grid item xs={6}>
Relationship
</Grid>
<Grid item xs={6}>
: {1 ?? '-'}
</Grid>
</Grid>
</Grid>
</Grid>
</Stack>
</TabPanel>
<TabPanel value={currentTab} index={'benefit'}> <TabPanel value={currentTab} index={'benefit'}>
<Grid container spacing={2}> <Grid container spacing={2}>
{ member && member?.current_plan?.corporate_benefits?.map((corporateBenefit, index) => {return ( { member && member?.current_plan?.corporate_benefits?.map((corporateBenefit, index) => {return (

View File

@@ -29,12 +29,18 @@ const setSession = (accessToken: string | null) => {
if (accessToken) { if (accessToken) {
localStorage.setItem('accessToken', accessToken); localStorage.setItem('accessToken', accessToken);
axios.defaults.headers.common.Authorization = `Bearer ${accessToken}`; axios.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
axios.defaults.headers.common['Accept-Language'] = (localStorage.getItem('currentLocale') ? localStorage.getItem('currentLocale') : 'id-ID');
axios.defaults.headers.common['Accept'] = 'application/json';
axios.defaults.headers.common['Content-Type'] = 'application/json';
// This function below will handle when token is expired // This function below will handle when token is expired
// const { exp } = jwtDecode(accessToken); // const { exp } = jwtDecode(accessToken);
// handleTokenExpired(exp); // handleTokenExpired(exp);
} else { } else {
localStorage.removeItem('accessToken'); localStorage.removeItem('accessToken');
delete axios.defaults.headers.common.Authorization; delete axios.defaults.headers.common.Authorization;
delete axios.defaults.headers.common['Accept-Language'];
delete axios.defaults.headers.common['Accept'];
delete axios.defaults.headers.common['Content-Type'];
} }
}; };

View File

@@ -10,6 +10,14 @@ export default defineConfig({
// comment this out if that isn't relevant for your project // comment this out if that isn't relevant for your project
build: { build: {
outDir: 'build', outDir: 'build',
chunkSizeWarningLimit: 100,
rollupOptions: {
onwarn(warning, warn) {
if (warning.code === 'MODULE_LEVEL_DIRECTIVE') {
return
}
warn(warning)
}}
}, },
plugins: [ plugins: [
react(), react(),

View File

@@ -0,0 +1,8 @@
<?php
return [
'success' => 'Request has been successfully processed.',
'server_error' => 'Internal server error.',
'not_found' => 'Data not found',
'password' => 'Password wrong. Please try again.'
];

View File

@@ -0,0 +1,8 @@
<?php
return [
'required' => 'The :attribute field is required.',
'invalid' => 'The :attribute field is invalid.',
'max' => ':attribute cannot exceed :length characters.',
'email' => 'Invalid email format.'
];

View File

@@ -0,0 +1,8 @@
<?php
return [
'success' => 'Request berhasil dilakukan.',
'server_error' => 'Internal server error.',
'not_found' => 'Data tidak ditemukan.',
'password' => 'Password salah. Silakan coba lagi.'
];

View File

@@ -0,0 +1,8 @@
<?php
return [
'required' => 'Kolom :attribute harus diisi.',
'invalid' => 'Kolom :attribute tidak valid.',
'max' => ':attribute tidak boleh melebihi :length karakter.',
'email' => 'Format email salah.'
];