From 53768735524eb3f4751e73e66919960ee323f8bc Mon Sep 17 00:00:00 2001 From: Tb Fajri Date: Fri, 6 Oct 2023 14:57:33 +0700 Subject: [PATCH] update --- .../Api/ClaimRequestController.php | 139 +++-- .../Api/CorporateCurrentController.php | 87 +++ Modules/Client/Routes/api.php | 4 + .../Api/Linksehat/PaymentController.php | 4 +- app/Builders/MemberBuilder.php | 45 +- database/seeders/ServiceSeeder.php | 4 +- .../client-portal/src/@types/corporates.ts | 198 +++++++ frontend/client-portal/src/@types/table.ts | 1 + .../client-portal/src/components/Table.tsx | 51 +- .../src/components/UploadImage.tsx | 128 +++++ .../components/hook-form/RHFAutocomplete.tsx | 41 ++ .../src/components/hook-form/RHFSwitch.tsx | 5 +- .../src/components/table/Index.ts | 1 + .../src/components/table/TableMoreMenu.tsx | 60 +++ .../layouts/dashboard/navbar/NavConfig.tsx | 20 + .../src/pages/AlarmCenter/List.tsx | 1 + .../src/pages/ClaimReport/List.tsx | 1 + .../pages/ClaimSubmit/DialogDetailClaim.tsx | 181 +++++++ .../src/pages/ClaimSubmit/Index.tsx | 217 ++++++++ .../src/pages/ClaimSubmit/List.tsx | 256 +++++++++ .../src/pages/Corporate/Form.tsx | 499 ++++++++++++++++++ .../src/pages/Corporate/Index.tsx | 142 +++++ .../src/pages/Corporate/List.tsx | 354 +++++++++++++ .../src/pages/Corporate/ServiceMonitoring.tsx | 348 ++++++++++++ .../src/pages/Corporate/Show.tsx | 469 ++++++++++++++++ .../src/pages/Corporate/UserProfile.tsx | 85 +++ .../src/pages/Dashboard/Index.tsx | 1 + frontend/client-portal/src/routes/index.tsx | 55 +- .../sections/claim-submit/CardClaimStatus.tsx | 102 ++++ .../sections/dashboard/DialogRequestLog.tsx | 2 +- .../client-portal/src/utils/formatTime.ts | 4 + .../dashboard/src/components/table/Index.ts | 1 + .../src/components/table/TableMoreMenu.tsx | 60 +++ .../src/pages/Corporates/Benefit/Index.tsx | 4 +- .../pages/Corporates/ClaimHistory/Index.tsx | 4 +- .../pages/Corporates/CorporatePlan/Index.tsx | 4 +- .../Corporates/CorporateTabNavigations.tsx | 2 +- .../Corporates/DiagnosisExclusion/Index.tsx | 4 +- .../src/pages/Corporates/Division/Index.tsx | 6 +- .../dashboard/src/pages/Corporates/Form.tsx | 120 ++++- .../pages/Corporates/Formularium/Index.tsx | 4 +- .../src/pages/Corporates/History.tsx | 13 +- .../src/pages/Corporates/Hospital/Index.tsx | 4 +- .../dashboard/src/pages/Corporates/Index.tsx | 75 ++- .../src/pages/Corporates/Member/Index.tsx | 4 +- .../src/pages/Corporates/Plan/Index.tsx | 4 +- .../src/pages/Corporates/Services/Index.tsx | 4 +- frontend/dashboard/src/routes/index.tsx | 2 +- frontend/dashboard/src/theme/overrides/Aso.ts | 10 + .../dashboard/src/theme/overrides/Table.ts | 3 +- 50 files changed, 3683 insertions(+), 150 deletions(-) create mode 100644 Modules/Client/Http/Controllers/Api/CorporateCurrentController.php create mode 100644 frontend/client-portal/src/@types/corporates.ts create mode 100644 frontend/client-portal/src/components/UploadImage.tsx create mode 100644 frontend/client-portal/src/components/hook-form/RHFAutocomplete.tsx create mode 100644 frontend/client-portal/src/components/table/Index.ts create mode 100644 frontend/client-portal/src/components/table/TableMoreMenu.tsx create mode 100644 frontend/client-portal/src/pages/ClaimSubmit/DialogDetailClaim.tsx create mode 100644 frontend/client-portal/src/pages/ClaimSubmit/Index.tsx create mode 100644 frontend/client-portal/src/pages/ClaimSubmit/List.tsx create mode 100644 frontend/client-portal/src/pages/Corporate/Form.tsx create mode 100644 frontend/client-portal/src/pages/Corporate/Index.tsx create mode 100644 frontend/client-portal/src/pages/Corporate/List.tsx create mode 100644 frontend/client-portal/src/pages/Corporate/ServiceMonitoring.tsx create mode 100644 frontend/client-portal/src/pages/Corporate/Show.tsx create mode 100644 frontend/client-portal/src/pages/Corporate/UserProfile.tsx create mode 100644 frontend/client-portal/src/sections/claim-submit/CardClaimStatus.tsx create mode 100644 frontend/dashboard/src/components/table/Index.ts create mode 100644 frontend/dashboard/src/components/table/TableMoreMenu.tsx create mode 100644 frontend/dashboard/src/theme/overrides/Aso.ts diff --git a/Modules/Client/Http/Controllers/Api/ClaimRequestController.php b/Modules/Client/Http/Controllers/Api/ClaimRequestController.php index c2aacf0b..9d194472 100644 --- a/Modules/Client/Http/Controllers/Api/ClaimRequestController.php +++ b/Modules/Client/Http/Controllers/Api/ClaimRequestController.php @@ -11,6 +11,7 @@ use App\Services\ClaimRequestService; use Illuminate\Contracts\Support\Renderable; use Illuminate\Http\Request; use Illuminate\Routing\Controller; +use Illuminate\Support\Facades\DB; class ClaimRequestController extends Controller { @@ -41,67 +42,75 @@ class ClaimRequestController extends Controller public function store(Request $request) { $request->validate([ - 'member_id' => 'required', - 'service_code' => 'required|in:OP,IP' + 'member_id' => 'required|array', + 'member_id.*' => 'required', + 'service_code.*' => 'required|in:OP,IP' ]); - $code = $this->getNextCode(); - $member = Member::find($request->member_id); - $newClaimRequest = ClaimRequestService::storeClaimRequest(code: $code, member: $member, paymentType: 'reimbursement', serviceCode: $request->service_code); - - ClaimRequested::dispatch($newClaimRequest); - - // Log History - $newClaimRequest->histories()->create([ - 'title' => 'New Claim Requested', - 'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})", - 'type' => 'info', - 'system_origin' => 'client-portal' - ]); - - if ($request->hasFile('result_files')) { - foreach ($request->result_files as $file) { - $pathFile = File::storeFile('claim-result', $newClaimRequest->id, $file); - $newClaimRequest->files()->updateOrCreate([ - 'type' => 'claim-result', - 'name' => File::getFileName('claim-result', $newClaimRequest->id, $file), - 'original_name' => $file->getClientOriginalName(), - 'extension' => $file->getClientOriginalExtension(), - 'path' => $pathFile, - 'created_by' => auth()->user()->id, - 'updated_by' => auth()->user()->id, + if ($request->member_id){ + foreach($request->member_id as $key => $member_id){ + + $code = $this->getNextCode(); + $member = Member::find($member_id); + $newClaimRequest = ClaimRequestService::storeClaimRequest(code: $code, member: $member, paymentType: 'reimbursement', serviceCode: $request->service_code[$key]); + + ClaimRequested::dispatch($newClaimRequest); + // Log History + $newClaimRequest->histories()->create([ + 'title' => 'New Claim Requested', + 'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})", + 'type' => 'info', + 'system_origin' => 'client-portal' ]); + + if ($request->hasFile('result_files')) { + foreach ($request->result_files[$key] as $file) { + $pathFile = File::storeFile('claim-result', $newClaimRequest->id, $file); + $newClaimRequest->files()->updateOrCreate([ + 'type' => 'claim-result', + 'name' => File::getFileName('claim-result', $newClaimRequest->id, $file), + 'original_name' => $file->getClientOriginalName(), + 'extension' => $file->getClientOriginalExtension(), + 'path' => $pathFile, + 'created_by' => auth()->user()->id, + 'updated_by' => auth()->user()->id, + ]); + } + } + + if ($request->hasFile('diagnosa_files')) { + foreach ($request->diagnosa_files[$key] as $file) { + $pathFile = File::storeFile('claim-diagnosis', $newClaimRequest->id, $file); + $newClaimRequest->files()->updateOrCreate([ + 'type' => 'claim-diagnosis', + 'name' => File::getFileName('claim-diagnosis', $newClaimRequest->id, $file), + 'original_name' => $file->getClientOriginalName(), + 'extension' => $file->getClientOriginalExtension(), + 'path' => $pathFile, + 'created_by' => auth()->user()->id, + 'updated_by' => auth()->user()->id, + ]); + } + } + + if ($request->hasFile('kondisi_files')) { + foreach ($request->kondisi_files[$key] as $file) { + $pathFile = File::storeFile('claim-kondisi', $newClaimRequest->id, $file); + $newClaimRequest->files()->updateOrCreate([ + 'type' => 'claim-kondisi', + 'name' => File::getFileName('claim-kondisi', $newClaimRequest->id, $file), + 'original_name' => $file->getClientOriginalName(), + 'extension' => $file->getClientOriginalExtension(), + 'path' => $pathFile, + 'created_by' => auth()->user()->id, + 'updated_by' => auth()->user()->id, + ]); + } + } } } + - if ($request->hasFile('diagnosa_files')) { - foreach ($request->diagnosa_files as $file) { - $pathFile = File::storeFile('claim-diagnosis', $newClaimRequest->id, $file); - $newClaimRequest->files()->updateOrCreate([ - 'type' => 'claim-diagnosis', - 'name' => File::getFileName('claim-diagnosis', $newClaimRequest->id, $file), - 'original_name' => $file->getClientOriginalName(), - 'extension' => $file->getClientOriginalExtension(), - 'path' => $pathFile, - 'created_by' => auth()->user()->id, - 'updated_by' => auth()->user()->id, - ]); - } - } - - if ($request->hasFile('kondisi_files')) { - foreach ($request->kondisi_files as $file) { - $pathFile = File::storeFile('claim-kondisi', $newClaimRequest->id, $file); - $newClaimRequest->files()->updateOrCreate([ - 'type' => 'claim-kondisi', - 'name' => File::getFileName('claim-kondisi', $newClaimRequest->id, $file), - 'original_name' => $file->getClientOriginalName(), - 'extension' => $file->getClientOriginalExtension(), - 'path' => $pathFile, - 'created_by' => auth()->user()->id, - 'updated_by' => auth()->user()->id, - ]); - } - } + return Helper::responseJson(data: $request->toArray(), message: 'Claim Request berhasil ajukan!'); } @@ -149,11 +158,25 @@ class ClaimRequestController extends Controller public static function getNextCode() { - $last_number = ClaimRequest::withTrashed()->max('code'); - $next_number = empty($last_number) ? 1 : ((int) explode('-', $last_number)[2] + 1); + // $last_number = ClaimRequest::max('code'); + // $next_number = empty($last_number) ? 1 : ((int) explode('-', $last_number)[2] + 1); + // return self::makeCode($next_number); + + $last_numeric_code = ClaimRequest::select(DB::raw('MAX(CAST(SUBSTRING_INDEX(code, "-", -1) AS SIGNED)) as max_numeric_code')) + ->whereRaw('SUBSTRING_INDEX(code, "-", -1) REGEXP "^[0-9]+$"') + ->value('max_numeric_code'); + // $next_number = 1; + if ($last_numeric_code) { + // // Jika ada kode sebelumnya, pecah kode dan tambahkan 1 ke angka terakhir + // $parts = explode('-', $last_code); + // $last_number = (int) end($parts); + $next_number = $last_numeric_code + 1; + } + return self::makeCode($next_number); } + public static function makeCode($next_number) { // Pastikan $next_number adalah integer positif diff --git a/Modules/Client/Http/Controllers/Api/CorporateCurrentController.php b/Modules/Client/Http/Controllers/Api/CorporateCurrentController.php new file mode 100644 index 00000000..52d88d3b --- /dev/null +++ b/Modules/Client/Http/Controllers/Api/CorporateCurrentController.php @@ -0,0 +1,87 @@ +with('currentPolicy', 'subCorporates') + ->withCount([ + 'employees', + 'corporateBenefits', + 'corporatePlans', + + // 'claims' + ]) + // ->where('type', 'corporate') + ->where('id', $id) + ->paginate(1); + + return $corporates; + } + + public function update(Request $request, $id) + { + + $validate = $request->validate([ + 'reason' => 'required', + ]); + + + try { + DB::beginTransaction(); + //karena pake formdata + $linkingRules = $request->linking_rules; + $linkingRules = explode(',', $linkingRules); + $corporate = Corporate::findOrFail($id); + $corporate->fill($request->all()); + $corporate->linking_rules = $linkingRules; + $corporate->save(); + + if ($request->hasFile('logo')) { + $pathFileAvatar = File::storeFile('avatar', $corporate->id, $request->file('logo')); + + $corporate->files()->updateOrCreate([ + 'type' => 'avatar', + 'name' => File::getFileName('avatar', $corporate->id, $request->file('logo')), + 'extension' => $request->file('logo')->getClientOriginalExtension(), + 'path' => $pathFileAvatar, + 'created_by' => auth()->user()->id, + 'updated_by' => auth()->user()->id, + ]); + } + + DB::commit(); + } catch (\Exception $e) { + DB::rollBack(); + throw $e; + } + + return $corporate; + } +} diff --git a/Modules/Client/Routes/api.php b/Modules/Client/Routes/api.php index a83ee008..cd3acf81 100644 --- a/Modules/Client/Routes/api.php +++ b/Modules/Client/Routes/api.php @@ -4,6 +4,7 @@ use Modules\Client\Http\Controllers\Api\AuthController; use Modules\Client\Http\Controllers\Api\CorporateDivisionController; use Modules\Client\Http\Controllers\Api\CorporateManageController; use Modules\Client\Http\Controllers\Api\CorporateMemberController; +use Modules\Client\Http\Controllers\Api\CorporateCurrentController; use Modules\Client\Http\Controllers\Api\MemberController; use Modules\Client\Http\Controllers\Api\CorporatePolicyController; use Modules\Client\Http\Controllers\Api\UserController; @@ -54,6 +55,9 @@ Route::prefix('client')->group(function () { // Route::get('topup', [TopUpController::class, 'get']); Route::post('topup', [TopUpController::class, 'store']); Route::get('claim-report/claim-status', [ClaimReportController::class, 'claimStatus']); + + Route::get('corporate', [CorporateCurrentController::class, 'index']); + Route::put('corporate-update', [CorporateCurrentController::class, 'update']); }); Route::get('claims/{id}', [ClaimController::class, 'show']); diff --git a/Modules/Internal/Http/Controllers/Api/Linksehat/PaymentController.php b/Modules/Internal/Http/Controllers/Api/Linksehat/PaymentController.php index 9fdc6b35..3769b58a 100644 --- a/Modules/Internal/Http/Controllers/Api/Linksehat/PaymentController.php +++ b/Modules/Internal/Http/Controllers/Api/Linksehat/PaymentController.php @@ -41,13 +41,13 @@ class PaymentController extends Controller // Appointment Start // if ($request->has('appointment_start')) { - $detail->where('dTanggalAppointment', '>=', $request->appointment_start); + $detail->where('dCreateOn', '>=', $request->appointment_start); // } else { // $detail->where('dTanggalAppointment', '>', now()->format('Y-m-d')); // } // if ($request->has('appointment_end')) { - $detail->where('dTanggalAppointment', '<=', $request->appointment_end); + $detail->where('dCreateOn', '<=', $request->appointment_end); // } else { // $detail->where('dTanggalAppointment', '<', now()->addDay(1)->format('Y-m-d')); // } diff --git a/app/Builders/MemberBuilder.php b/app/Builders/MemberBuilder.php index 1b16e396..f2e60f8e 100644 --- a/app/Builders/MemberBuilder.php +++ b/app/Builders/MemberBuilder.php @@ -24,9 +24,24 @@ class MemberBuilder extends Builder public function joinCorporateEmployees(string $value = 'join'): static { + // return match ($value) { + // 'join' => $this->join('corporate_employees', 'members.id', '=', 'corporate_employees.member_id'), + // 'left' => $this->leftJoin('corporate_employees', 'members.id', '=', 'corporate_employees.member_id') + // }; + return match ($value) { - 'join' => $this->join('corporate_employees', 'members.id', '=', 'corporate_employees.member_id'), - 'left' => $this->leftJoin('corporate_employees', 'members.id', '=', 'corporate_employees.member_id') + 'join' => $this->join('corporate_employees', function ($join) { + $join->on('members.id', '=', 'corporate_employees.member_id') + ->orWhere('members.principal_id', '=', 'corporate_employees.member_id'); + }), + 'left' => $this->leftJoin('corporate_employees', function ($join) { + $join->on('members.id', '=', 'corporate_employees.member_id') + ->orWhere('members.principal_id', '=', 'corporate_employees.member_id'); + }), + 'right' => $this->rightJoin('corporate_employees', function ($join) { + $join->on('members.id', '=', 'corporate_employees.member_id') + ->orWhere('members.principal_id', '=', 'corporate_employees.member_id'); + }) }; } @@ -40,11 +55,31 @@ class MemberBuilder extends Builder public function joinClaimRequests(string $value = 'join'): static { + // return match ($value) { + // 'join' => $this->join('claim_requests', 'members.id', '=', 'claim_requests.member_id'), + // 'left' => $this->leftJoin('claim_requests', 'members.id', '=', 'claim_requests.member_id'), + // // 'right' => $this->rightJoin('claim_requests', 'members.id', '=', 'claim_requests.member_id') + // 'right' => $this->rightJoin('claim_requests', function ($join) { + // $join->on('members.id', '=', 'claim_requests.member_id') + // ->orWhere('members.principal_id', '=', 'claim_requests.member_id'); + // }) + // }; + return match ($value) { - 'join' => $this->join('claim_requests', 'members.id', '=', 'claim_requests.member_id'), - 'left' => $this->leftJoin('claim_requests', 'members.id', '=', 'claim_requests.member_id'), - 'right' => $this->rightJoin('claim_requests', 'members.id', '=', 'claim_requests.member_id') + 'join' => $this->join('claim_requests', function ($join) { + $join->on('members.id', '=', 'claim_requests.member_id') + ->orWhere('members.principal_id', '=', 'claim_requests.member_id'); + }), + 'left' => $this->leftJoin('claim_requests', function ($join) { + $join->on('members.id', '=', 'claim_requests.member_id') + ->orWhere('members.principal_id', '=', 'claim_requests.member_id'); + }), + 'right' => $this->rightJoin('claim_requests', function ($join) { + $join->on('members.id', '=', 'claim_requests.member_id') + ->orWhere('members.principal_id', '=', 'claim_requests.member_id'); + }) }; + } public function joinMemberPlans(string $value = 'join'): static diff --git a/database/seeders/ServiceSeeder.php b/database/seeders/ServiceSeeder.php index f98f6bf2..95d0443a 100644 --- a/database/seeders/ServiceSeeder.php +++ b/database/seeders/ServiceSeeder.php @@ -19,9 +19,9 @@ class ServiceSeeder extends Seeder $services = [ [ 'id' => 1, - 'name' => 'Out Patient', + 'name' => 'Outpatient', 'code' => 'OP', - 'description' => 'Out Patient', + 'description' => 'Outpatient', ], [ 'id' => 2, diff --git a/frontend/client-portal/src/@types/corporates.ts b/frontend/client-portal/src/@types/corporates.ts new file mode 100644 index 00000000..f8aaf228 --- /dev/null +++ b/frontend/client-portal/src/@types/corporates.ts @@ -0,0 +1,198 @@ +// ---------------------------------------------------------------------- + +export type Corporate = { + id: number; + code: string; + name?: string; + reason?: string; + payor_id?: string; + welcome_message?: string; + automatic_linking?: boolean; + linking_rules?: string; + type?: string; + avatar_url?: string; + help_text?: string; + logo?: any; + logo_url?: string; + active: boolean | number; + divisions?: Division[]; + employees?: Employee[]; + current_policy?: Policy; +}; + +export type Division = { + id: number; + corporate_id: number; + code: string; + name?: string; +} + +export type Employee = { + id: number; + name: string; +} + +export type Policy = { + id: number; + corporate_id: number; + code: string; + total_premi: number; + minimal_deposit_percentage: number; + minimal_deposit_net: number; + minimal_alert_percentage: number; + minimal_alert_net: number; + minimal_stop_service_percentage: number; + minimal_stop_service_net: number; + start: string | Date; + end: string | Date; +} + +export type CorporatePlan = { + id: number; + corporate_id: number; + code: string; + name: string; + description: string | null; + active: boolean | number; +} + +export type Plan = { + id: number; + corporate_plan: CorporatePlan | null; + service_code: string; + corporate_plan_id: string; + code: string; + type: string; + start: string; + end: string; + require_referral: string; + referral_source: string; + referral_duration: string; + family_plan: string; + family_plan_share_rules: string; + limit_rules: string; + layer: string; + layer_conditions: string; + budget_type: string; + budget_code: string; + budget_conditions: string; + surgery_limit: string; + non_surgery_limit: string; + max_claim_limit: string; + max_claim_count: string; + area_limit: string; + limit_shared_plans: string; + limit_shared_plan_type: string; + cashless_percentage: string; + reimbursement_percentage: string; + digital_percentage: string; + co_share_m_percentage: string; + co_share_s_percentage: string; + co_share_c_percentage: string; + cashless_deductible: string; + reimbursement_deductible: string; + digital_deductible: string; + co_share_m_deductible: string; + co_share_s_deductible: string; + co_share_c_deductible: string; + co_share_deductible_condition: string; + msc: string; + genders: string; + min_age: string; + max_age: string; + rule_of_excess: string; + max_excess_covered: string; + prorate_type: string; + prorate_lookup: string; + currency: string; + max_surgery_reinstatement_days: string; + max_surgery_periode_days: string; +} + +export type CorporateBenefit = { + id: number; + corporate_id: number; + code: string; + name: string; + description: string | null; + active: boolean | number; +} + +export type Benefit = { + service_code : string; + plan_code : string; + benefit_code : string; + code : string; + description : string; + budget : string; + budget_conditions : string; + budget_code : string; + primary_benefit_code : string; + benefit_mode : string; + room_class_coverage : string; + max_bed_coverage : string; + tolerance_parameter : string; + max_room_class : string; + limit_amount : string; + area_limit : string; + shared_benefit : string; + shared_benefit_type : string; + msc : string; + genders : string; + min_age : string; + max_age : string; + max_frequency_period : string; + daily_frequency : string; + weekly_frequency : string; + monthly_frequency : string; + yearly_frequency : string; + custom_frequency_days : string; + custom_duration_value : string; + allowed_transaction_types : string; + high_plan_factor : string; + pre_post_treatment : string; + pre_treatment_days : string; + post_treatment_days : string; + layer_type_1 : string; + layer_value_1 : string; + layer_type_2 : string; + layer_value_2 : string; + cashless_percentage : string; + reimbursement_percentage : string; + digital_percentage : string; + co_share_m_percentage : string; + co_share_s_percentage : string; + co_share_c_percentage : string; + cashless_deductible : string; + reimbursement_deductible : string; + digital_deductible : string; + co_share_m_deductible : string; + co_share_s_deductible : string; + co_share_c_deductible : string; + prorate_type : string; + prorate_lookup : string; + max_days_for_disability : string; + max_period_for_disability : string; + currency : string; + show_benefit_item : string; + show_benefit_value : string; +} + +export type CorporateService = { + id?: string | number; + corporate_id?: string | number; + description?: string; + name?: string; + service_code: string; + reason: string; + status: string; + configurations: any; +} + +export type MasterExclusion = { + id?: string | number; + name?: string; + code: string; + description?: string; +} + diff --git a/frontend/client-portal/src/@types/table.ts b/frontend/client-portal/src/@types/table.ts index 4ba7bafc..2f95319e 100644 --- a/frontend/client-portal/src/@types/table.ts +++ b/frontend/client-portal/src/@types/table.ts @@ -71,6 +71,7 @@ export type TableListProps = { setAppliedParams: Dispatch>; }; searchs: { + useSearchs: boolean; searchText: string; setSearchText: Dispatch>; handleSearchSubmit: (event: FormEvent) => void; diff --git a/frontend/client-portal/src/components/Table.tsx b/frontend/client-portal/src/components/Table.tsx index 2f7e86f9..3d082c1a 100644 --- a/frontend/client-portal/src/components/Table.tsx +++ b/frontend/client-portal/src/components/Table.tsx @@ -153,7 +153,7 @@ export default function Table({ /* -------------------------------------------------------------------------- */ return ( - + // {/* Field 1 */} @@ -192,20 +192,39 @@ export default function Table({ - ) : ( - -
- searchs.setSearchText(event.target.value)} - value={searchs.searchText} - fullWidth - /> - -
- )} + ) : null + // ( + // + //
+ // searchs.setSearchText(event.target.value)} + // value={searchs.searchText} + // fullWidth + // /> + // + //
+ // ) + } + + {searchs && searchs.useSearchs ? ( + + +
+ searchs.setSearchText(event.target.value)} + value={searchs.searchText} + fullWidth + /> + +
+
+ ) : null }
{/* End Field 1 */} @@ -263,6 +282,6 @@ export default function Table({ {/* End Field 2 */} -
+ //
); } diff --git a/frontend/client-portal/src/components/UploadImage.tsx b/frontend/client-portal/src/components/UploadImage.tsx new file mode 100644 index 00000000..a69c73ec --- /dev/null +++ b/frontend/client-portal/src/components/UploadImage.tsx @@ -0,0 +1,128 @@ +import React, { Dispatch, FunctionComponent, useCallback, useState } from 'react'; + +import { useDropzone } from 'react-dropzone'; +import { Box, Stack, Typography } from '@mui/material'; +import BlockContent from './upload/BlockContent'; +import { styled } from '@mui/material/styles'; +import { UploadIllustration } from '../assets'; +import Iconify from './Iconify'; + +const RootStyle = styled('div')(({ theme }) => ({ + width: 144, + height: 144, + margin: 'auto', + borderRadius: '50%', + padding: theme.spacing(1), + border: `2px dashed ${theme.palette.grey[500_32]}`, +})); +const DropZoneStyle = styled('div')({ + zIndex: 0, + width: '100%', + height: '100%', + outline: 'none', + display: 'flex', + overflow: 'hidden', + borderRadius: '50%', + position: 'relative', + alignItems: 'center', + justifyContent: 'center', + '& > *': { width: '100%', height: '100%' }, + '&:hover': { + cursor: 'pointer', + '& .placeholder': { + zIndex: 9, + }, + }, +}); + +const PlaceholderStyle = styled('div')(({ theme }) => ({ + display: 'flex', + position: 'absolute', + alignItems: 'center', + flexDirection: 'column', + justifyContent: 'center', + color: theme.palette.text.secondary, + // backgroundColor: theme.palette.background.neutral, + transition: theme.transitions.create('opacity', { + easing: theme.transitions.easing.easeInOut, + duration: theme.transitions.duration.shorter, + }), + '&:hover': { opacity: 0.72 }, +})); + +const UploadImage: FunctionComponent<{ + setFile: Dispatch; + currentImage: string; +}> = ({ setFile, currentImage, setSave, error, file, helperText, sx, ...other }) => { + const onDrop = useCallback( + (acceptedFiles) => { + // Do something with the files + console.log(acceptedFiles); + setFile(acceptedFiles[0]); + setImage(acceptedFiles[0]); + }, + [setFile, setSave] + ); + + const { getRootProps, getInputProps, isDragActive, isDragReject } = useDropzone({ + onDrop, + multiple: false, + }); + + const [image, setImage] = useState(null); + + return ( + + + + {/* */} + {image ? ( + preview + ) : currentImage ? ( + preview + ) : ( + + + {image ? 'Update photo' : 'Upload photo'} + + )} + + + + {image ? 'Update photo' : 'Upload photo'} + + {/* */} + {/* */} + + {isDragReject &&

Unsupported file type...

} +
+
+ ); +}; + +export default UploadImage; diff --git a/frontend/client-portal/src/components/hook-form/RHFAutocomplete.tsx b/frontend/client-portal/src/components/hook-form/RHFAutocomplete.tsx new file mode 100644 index 00000000..3872aec5 --- /dev/null +++ b/frontend/client-portal/src/components/hook-form/RHFAutocomplete.tsx @@ -0,0 +1,41 @@ +import { Autocomplete, TextField, TextFieldProps } from '@mui/material'; +import { useState } from 'react'; +import { Controller, useFormContext } from 'react-hook-form'; + +interface IProps { + options: any[]; + name: string; + label?: string; +} + +export default function RHFAutocomplete({ name, options, label, ...other }: IProps & TextFieldProps) { + const { control } = useFormContext(); + console.log(control) + + const [value, setValue] = useState(options[0]); + const [inputValue, setInputValue] = useState(''); + + return ( + ( + { + // console.log('fuck', newValue) + setValue(newValue.id); + }} + inputValue={inputValue} + onInputChange={(event, newInputValue) => { + setInputValue(newInputValue); + }} + renderInput={(params) => } + {...other} + /> + )} + /> + ); +} \ No newline at end of file diff --git a/frontend/client-portal/src/components/hook-form/RHFSwitch.tsx b/frontend/client-portal/src/components/hook-form/RHFSwitch.tsx index a56c548a..3110e5b2 100644 --- a/frontend/client-portal/src/components/hook-form/RHFSwitch.tsx +++ b/frontend/client-portal/src/components/hook-form/RHFSwitch.tsx @@ -9,9 +9,10 @@ type IProps = Omit; interface Props extends IProps { name: string; + disabled?: boolean; } -export default function RHFSwitch({ name, ...other }: Props) { +export default function RHFSwitch({ name, disabled = false, ...other }: Props) { const { control } = useFormContext(); return ( @@ -20,7 +21,7 @@ export default function RHFSwitch({ name, ...other }: Props) { } + render={({ field }) => } /> } {...other} diff --git a/frontend/client-portal/src/components/table/Index.ts b/frontend/client-portal/src/components/table/Index.ts new file mode 100644 index 00000000..8b4b0f88 --- /dev/null +++ b/frontend/client-portal/src/components/table/Index.ts @@ -0,0 +1 @@ +export { default as TableMoreMenu } from './TableMoreMenu'; \ No newline at end of file diff --git a/frontend/client-portal/src/components/table/TableMoreMenu.tsx b/frontend/client-portal/src/components/table/TableMoreMenu.tsx new file mode 100644 index 00000000..6fe3f43e --- /dev/null +++ b/frontend/client-portal/src/components/table/TableMoreMenu.tsx @@ -0,0 +1,60 @@ +import { useEffect, useState } from 'react'; +// @mui +import { IconButton } from '@mui/material'; +// +import Iconify from '../Iconify'; +import MenuPopover from '../MenuPopover'; + +// ---------------------------------------------------------------------- + +type Props = { + actions: React.ReactNode; + disableRipple?: boolean; +}; + +export default function TableMoreMenu({ actions, disableRipple }: Props) { + const [open, setOpen] = useState(null); + + // Close menu popover + useEffect(() => { + setOpen(null); + }, [actions]) + + const handleOpen = (event: React.MouseEvent) => { + setOpen(event.currentTarget); + }; + + const handleClose = () => { + setOpen(null); + }; + + return ( + <> + + + + + + {actions} + +     +  ); +} \ No newline at end of file diff --git a/frontend/client-portal/src/layouts/dashboard/navbar/NavConfig.tsx b/frontend/client-portal/src/layouts/dashboard/navbar/NavConfig.tsx index 4859a683..f7cfa648 100644 --- a/frontend/client-portal/src/layouts/dashboard/navbar/NavConfig.tsx +++ b/frontend/client-portal/src/layouts/dashboard/navbar/NavConfig.tsx @@ -6,6 +6,21 @@ const navConfig = [ { items: [{ title: 'Dashboard', path: '/dashboard' }], }, + + // Corporate + // ---------------------------------------------------------------------- + { + subheader: 'Corporate', + items: [ + { + title: 'Corporate', + path: '/corporate', + // icon: ICONS.default, + }, + ], + }, + + // Alarm Center // ---------------------------------------------------------------------- { @@ -15,6 +30,10 @@ const navConfig = [ title: 'Alarm Center', path: '/alarm-center', }, + { + title: 'Claim Submit', + path: '/claim-submit', + }, { title: 'Claim Report', path: '/claim-report', @@ -22,6 +41,7 @@ const navConfig = [ ], }, + // User Management // ---------------------------------------------------------------------- // { diff --git a/frontend/client-portal/src/pages/AlarmCenter/List.tsx b/frontend/client-portal/src/pages/AlarmCenter/List.tsx index 27c13602..d0375d7d 100644 --- a/frontend/client-portal/src/pages/AlarmCenter/List.tsx +++ b/frontend/client-portal/src/pages/AlarmCenter/List.tsx @@ -221,6 +221,7 @@ export default function List() { }; const searchs = { + useSearchs: true, searchText: searchText, setSearchText: setSearchText, handleSearchSubmit: handleSearchSubmit, diff --git a/frontend/client-portal/src/pages/ClaimReport/List.tsx b/frontend/client-portal/src/pages/ClaimReport/List.tsx index 6da864b9..9b2e2c31 100644 --- a/frontend/client-portal/src/pages/ClaimReport/List.tsx +++ b/frontend/client-portal/src/pages/ClaimReport/List.tsx @@ -100,6 +100,7 @@ export default function List() { }; const searchs = { + useSearchs: true, searchText: searchText, setSearchText: setSearchText, handleSearchSubmit: handleSearchSubmit, diff --git a/frontend/client-portal/src/pages/ClaimSubmit/DialogDetailClaim.tsx b/frontend/client-portal/src/pages/ClaimSubmit/DialogDetailClaim.tsx new file mode 100644 index 00000000..01df6b98 --- /dev/null +++ b/frontend/client-portal/src/pages/ClaimSubmit/DialogDetailClaim.tsx @@ -0,0 +1,181 @@ +// @mui +import { + Button, + Box, + Stepper, + Step, + StepLabel, + Card, + Typography, + Divider, + Stack, +} from '@mui/material'; +import { Add } from '@mui/icons-material'; +// components +import MuiDialog from '../../components/MuiDialog'; +// theme +import palette from '../../theme/palette'; +// React +import { ReactElement } from 'react'; + +type DataContent = { + info: string; + date: string; + time: string; +}; + +type MuiDialogProps = { + title?: { + name?: string; + icon?: string; + }; + openDialog: boolean; + setOpenDialog: Function; + content?: ReactElement; + data?: DataContent[]; +}; + +const steps = ['Review', 'Approval', 'Disbursement']; + +const DialogDetailClaim = ({ title, openDialog, setOpenDialog, data }: MuiDialogProps) => { + function clickHandler(arg0: string) { + throw new Error('Function not implemented.'); + } + + // const getContent = () => ( + + // ); + + return ( + <> + + + Claim Request + + + Submission date + 15 / 05 / 2022 + + + + + {steps.map((label) => ( + + {label} + + ))} + + + + + 17 Mei 2022 + + + + + + {/* Item 1 */} + + + 09:10 WIB + + Approval + + + + + + Details : mohon melengkapi kekurangan dokumen + + + Lab pemeriksaan darah + + + + + {/* Item 2 */} + + + 09:00 WIB + + Approval + + + + + + Details : Penilaian Dokter + + + + {/* Item 3 */} + + + 08:00 WIB + + Review + + + + + + Details : Klaim Diajukan + + + + + + + // + ); +}; + +export default DialogDetailClaim; diff --git a/frontend/client-portal/src/pages/ClaimSubmit/Index.tsx b/frontend/client-portal/src/pages/ClaimSubmit/Index.tsx new file mode 100644 index 00000000..b54211ec --- /dev/null +++ b/frontend/client-portal/src/pages/ClaimSubmit/Index.tsx @@ -0,0 +1,217 @@ +/* ---------------------------------- react --------------------------------- */ +import { useContext, useEffect, useState } from 'react'; +/* ----------------------------------- mui ---------------------------------- */ +import { Container, Grid } from '@mui/material'; +/* ------------------------------- components ------------------------------- */ +import Page from '../../components/Page'; +import TableList from '../../components/Table'; +/* ---------------------------------- hooks --------------------------------- */ +import useSettings from '../../hooks/useSettings'; +/* -------------------------------- sections -------------------------------- */ +import CardClaimStatus from '../../sections/claim-submit/CardClaimStatus'; +/* ---------------------------------- utils --------------------------------- */ +import axios from '../../utils/axios'; +/* --------------------------------- context -------------------------------- */ +import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; +/* --------------------------------- orders --------------------------------- */ +import { HeadCell, Order, PaginationTableProps } from '../../@types/table'; +import { useSearchParams } from 'react-router-dom'; +import List from './List'; +import ClaimItems from '../Claims/components/ClaimItems'; +import DiagnosisHistory from '../Claims/components/DiagnosisHistory'; +import Documents from '../Claims/components/Documents'; +// theme +import palette from '../../theme/palette'; +import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs'; + +interface ClaimStatusType { + name: string; + value: number; + color: string; +} + +export default function Drugs() { + const { themeStretch } = useSettings(); + const { corporateValue } = useContext(UserCurrentCorporateContext); + + const [listClaimStatusItems, setListClaimStatusItems] = useState([]); + const [listAllMemberByClaimStatus, setListAllMemberByClaimStatus] = useState([]); + + /* -------------------------------------------------------------------------- */ + /* setTable */ + /* -------------------------------------------------------------------------- */ + + 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('asc'); + const [orderBy, setOrderBy] = useState('fullName'); + + 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({ + 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, + }; + /* -------------------------------------------------------------------------- */ + + /* -------------------------------- headCell -------------------------------- */ + const headCells: HeadCell[] = [ + { + id: 'memberId', + align: 'left', + label: 'Member ID', + isSort: true, + }, + { + id: 'codeRequest', + align: 'left', + label: 'Code Request', + isSort: true, + }, + { + id: 'fullName', + align: 'center', + label: 'Name', + isSort: true, + }, + { + id: 'division', + align: 'center', + label: 'Divisi', + isSort: true, + }, + { + id: 'submissionDate', + align: 'center', + label: 'Submission Date', + isSort: true, + }, + { + id: 'status', + align: 'center', + label: 'Status', + isSort: true, + }, + ]; + /* -------------------------------------------------------------------------- */ + + useEffect(() => { + (async () => { + setIsLoading(true); + + const claimStatus = await axios.get(`${corporateValue}/claim-report/claim-status`); + + setListClaimStatusItems([ + { + name: 'Requested', + value: claimStatus.data.data.requesteds, + color: palette.dark.primary.dark, + }, + { + name: 'Approval', + value: claimStatus.data.data.approveds, + color: palette.dark.warning.dark, + }, + { + name: 'Rejected', + value: claimStatus.data.data.rejecteds, + color: palette.dark.error.dark, + }, + ]); + + const parameters = + Object.keys(appliedParams).length !== 0 + ? appliedParams + : Object.fromEntries([ + ...searchParams.entries(), + ['order', orders.order], + ['orderBy', orders.orderBy], + ]); + + const claim = await axios.get(`${corporateValue}/members`, { + params: { ...parameters, type: 'claim-report' }, + }); + + setSearchParams(parameters); + + setListAllMemberByClaimStatus(claim.data.data.allMembersByClaimStatus.data); + setPaginationTable(claim.data.data.allMembersByClaimStatus); + + setIsLoading(false); + })(); + }, [appliedParams, searchParams, order, orderBy, setSearchParams, corporateValue]); + + return ( + + + + + + + + {/* */} + + + + + ); +} diff --git a/frontend/client-portal/src/pages/ClaimSubmit/List.tsx b/frontend/client-portal/src/pages/ClaimSubmit/List.tsx new file mode 100644 index 00000000..9b2e2c31 --- /dev/null +++ b/frontend/client-portal/src/pages/ClaimSubmit/List.tsx @@ -0,0 +1,256 @@ +/* ---------------------------------- @mui ---------------------------------- */ +import { Stack, Button } from '@mui/material'; +/* ---------------------------------- axios --------------------------------- */ +// import axios from 'axios'; +import axios from '../../utils/axios'; +/* ---------------------------------- 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 } from '../../utils/formatTime'; + +export default function List() { + const navigate = useNavigate(); + + const { corporateValue } = useContext(UserCurrentCorporateContext); + + const [data, setData] = useState([]); + + /* -------------------------------------------------------------------------- */ + /* 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('desc'); + const [orderBy, setOrderBy] = useState('codeRequest'); + + 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({ + 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 search ----------------------------- */ + const [searchText, setSearchText] = useState(''); + + const handleSearchSubmit = async (event: React.FormEvent) => { + 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, + }; + + /* -------------------------------- headCell -------------------------------- */ + const headCells: HeadCell[] = [ + { + id: 'memberId', + align: 'left', + label: 'Member ID', + isSort: true, + }, + { + id: 'codeRequest', + align: 'left', + label: 'Code Request', + isSort: true, + }, + { + id: 'submissionDate', + align: 'left', + label: 'Request Date', + isSort: true, + }, + { + id: 'fullName', + align: 'left', + label: 'Name', + isSort: true, + }, + + { + id: 'division', + align: 'left', + label: 'Divisi', + isSort: false, + }, + { + id: 'status', + align: 'center', + label: 'Status', + isSort: false, + }, + { + id: 'action', + align: 'right', + label: '', + isSort: false, + }, + ]; + + useEffect(() => { + (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(`${corporateValue}/members`, { + params: { ...parameters, type: 'claim-report' }, + }); + + setData( + response.data.data.map((obj: any) => ({ + ...obj, + status: + obj.status === 'requested' ? ( + + ) : obj.status === 'approved' ? ( + + ) : ( + + ), + submissionDate: + obj.submissionDate ? fDate(obj.submissionDate) : '' + })) + ); + + 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); + } + + setIsLoading(false); + })(); + }, [appliedParams, searchParams, order, orderBy, setSearchParams, corporateValue]); + + return ( + + + + ); +} diff --git a/frontend/client-portal/src/pages/Corporate/Form.tsx b/frontend/client-portal/src/pages/Corporate/Form.tsx new file mode 100644 index 00000000..22f19272 --- /dev/null +++ b/frontend/client-portal/src/pages/Corporate/Form.tsx @@ -0,0 +1,499 @@ +import * as Yup from 'yup'; +import { useSnackbar } from 'notistack'; +import { useNavigate } from 'react-router-dom'; +import { useContext, useCallback, useEffect, useMemo, useState } from 'react'; +// form +import { Controller, useForm } from 'react-hook-form'; +import { yupResolver } from '@hookform/resolvers/yup'; +// @mui +import { styled } from '@mui/material/styles'; +import { LoadingButton } from '@mui/lab'; +import { + Box, + Button, + Card, + FormControl, + FormControlLabel, + FormHelperText, + FormLabel, + Grid, + InputLabel, + Menu, + MenuItem, + OutlinedInput, + Radio, + RadioGroup, + Select, + SelectChangeEvent, + Stack, + Typography, +} from '@mui/material'; + +// components +import { + FormProvider, + RHFTextField, + RHFRadioGroup, + RHFUploadAvatar, + RHFSwitch, + RHFEditor, + RHFDatepicker, + RHFMultiCheckbox, + RHFCheckbox, + RHFCustomMultiCheckbox, + RHFSelect, +} from '../../components/hook-form'; +import { Corporate } from '../../@types/corporates'; +import axios from '../../utils/axios'; +import { fCurrency } from '../../utils/formatNumber'; +// import RHFAutocomplete from '../../components/hook-form/RHFAutocomplete'; +import UploadImage from '../../components/UploadImage'; +import { fPostFormat } from '../../utils/formatTime'; +import AddIcon from '@mui/icons-material/Add'; +import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; +// import Link from '@/theme/overrides/Link'; + +const LabelStyle = styled(Typography)(({ theme }) => ({ + ...theme.typography.subtitle2, + color: theme.palette.text.secondary, + marginBottom: theme.spacing(1), +})); + +interface FormValuesProps extends Partial { + taxes: boolean; + inStock: boolean; +} + +type Props = { + // isEdit: boolean; + currentCorporate?: Corporate; +}; + +export default function CorporateForm({currentCorporate }: Props) { + const navigate = useNavigate(); + const [corporate_groups, setCorporateGroups] = useState([]); + const { corporateValue } = useContext(UserCurrentCorporateContext); + // const [ errors, setErrors ] = useState<{ [key: string]: string }>({}); + + const { enqueueSnackbar } = useSnackbar(); + let NewCorporateSchema = Yup.object().shape({ + welcome_message: Yup.string().required('Welcome Message is required'), + // reason: Yup.string().required('Reason for update is required when editing data'), + }); + + const defaultValues = useMemo( + () => ({ + code: currentCorporate?.code || '', + name: currentCorporate?.name || '', + reason: currentCorporate?.reason || '', + payor_id: currentCorporate?.payor_id || '', + welcome_message: currentCorporate?.welcome_message || '', + help_text: currentCorporate?.help_text || '', + active: currentCorporate?.id ? currentCorporate?.active === 1 : true, + automatic_linking: currentCorporate?.id ? currentCorporate?.automatic_linking === 1 : true, + policy_id: currentCorporate?.current_policy?.id || '', + policy_code: currentCorporate?.current_policy?.code || '', + policy_total_premi: currentCorporate?.current_policy?.total_premi || 0, + policy_minimal_deposit_percentage: + currentCorporate?.current_policy?.minimal_deposit_percentage || 50, + policy_minimal_deposit_net: currentCorporate?.current_policy?.minimal_deposit_net || 0, + policy_minimal_alert_percentage: + currentCorporate?.current_policy?.minimal_alert_percentage || 25, + policy_minimal_alert_net: currentCorporate?.current_policy?.minimal_alert_net || 0, + policy_stop_service_percentage: + currentCorporate?.current_policy?.minimal_stop_service_percentage || 25, + policy_stop_service_net: currentCorporate?.current_policy?.minimal_stop_service_net || 0, + policy_start: currentCorporate?.current_policy?.start || '', + policy_end: currentCorporate?.current_policy?.end || '', + linking_rules: currentCorporate?.linking_rules || ['nric', 'nik', 'member_id'], + type: currentCorporate?.type || 'corporate', + logo: currentCorporate?.logo || '', + }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [currentCorporate] + ); + + const methods = useForm({ + resolver: yupResolver(NewCorporateSchema), + defaultValues, + }); + + const { + reset, + watch, + control, + setValue, + getValues, + setError, + handleSubmit, + formState: { isSubmitting }, + } = methods; + + const values = watch(); + + useEffect(() => { + axios + .get(`/${corporateValue}/corporate`) + .then((res) => { + // console.log(res.data.data[0], 'tussr') + const data = res.data.data[0]; + setCorporateGroups(res.data.data[0]); + reset({ + code: data?.code || '', + name: data?.name || '', + reason: data?.reason || '', + payor_id: data?.payor_id || '', + welcome_message: data?.welcome_message || '', + help_text: data?.help_text || '', + active: data?.id ? data?.active === 1 : true, + automatic_linking: data?.id ? data?.automatic_linking === 1 : true, + policy_id: data?.current_policy?.id || '', + policy_code: data?.current_policy?.code || '', + policy_total_premi: data?.current_policy?.total_premi || 0, + policy_minimal_deposit_percentage: + data?.current_policy?.minimal_deposit_percentage || 50, + policy_minimal_deposit_net: data?.current_policy?.minimal_deposit_net || 0, + policy_minimal_alert_percentage: + data?.current_policy?.minimal_alert_percentage || 25, + policy_minimal_alert_net: data?.current_policy?.minimal_alert_net || 0, + policy_stop_service_percentage: + data?.current_policy?.minimal_stop_service_percentage || 25, + policy_stop_service_net: data?.current_policy?.minimal_stop_service_net || 0, + policy_start: data?.current_policy?.start || '', + policy_end: data?.current_policy?.end || '', + linking_rules: data?.linking_rules || ['nric', 'nik', 'member_id'], + type: data?.type || 'corporate', + logo: data?.logo || '', + }); + }) + .catch((err) => { + enqueueSnackbar('Opps, failed to get Corporate Group List', { variant: 'error' }); + }); + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentCorporate]); + const currentImage = currentCorporate?.avatar_url; + const [file, setFile] = useState(null); + const [save, setSave] = useState(null); + + // console.log('save', save); + + const onSubmit = async (data: FormValuesProps) => { + try { + const formData = new FormData(); + formData.append('logo', file); + formData.append('name', data.name); + formData.append('automatic_linking', data.automatic_linking ? 1 : 0); + formData.append('welcome_message', data.welcome_message); + formData.append('reason', data.reason); + formData.append('help_text', data.help_text); + formData.append('linking_rules', data.linking_rules); + + // console.log('MOTHERFUCKER', data.linking_rules) + formData.append('_method', 'PUT'); + const response = await axios.post(`/${corporateValue}/corporate-update`, formData); + + reset(); + enqueueSnackbar( + 'Corporate Updated Successfully!', + { variant: 'success' } + ); + navigate('/corporate'); + } catch (error: any) { + if (error && error.response.status === 422) { + // for (const [key, value] of Object.entries(error.response.data.errors)) { + // setError(key, { message: value[0] }); + // enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' }); + // } + for (const [key, value] of Object.entries(error.response.data.errors)) { + // setError(key, { message: value[0] }); + enqueueSnackbar(value ?? 'Failed Processing Request', { variant: 'error' }); + } + } else { + enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' }); + } + } + }; + + const handleDrop = useCallback( + (acceptedFiles) => { + setValue( + 'logo', + acceptedFiles.map((file: Blob | MediaSource) => + Object.assign(file, { + preview: URL.createObjectURL(file), + }) + ) + ); + }, + [setValue] + ); + + const handleRemove = (file: File | string) => { + setValue('logo', null); + }; + + // Only Handle Change on Policy Total Premi + useEffect(() => { + let calc_policy_minimal_deposit_net = + (values.policy_total_premi * values.policy_minimal_deposit_percentage) / 100; + setValue('policy_minimal_deposit_net', calc_policy_minimal_deposit_net); + + let calc_policy_minimal_alert_net = + (values.policy_total_premi * values.policy_minimal_alert_percentage) / 100; + setValue('policy_minimal_alert_net', calc_policy_minimal_alert_net); + + let calc_policy_stop_service_net = + (values.policy_total_premi * values.policy_stop_service_percentage) / 100; + setValue('policy_stop_service_net', calc_policy_stop_service_net); + }, [values.policy_total_premi]); + + // Only Handle on Change Policy Minimal Deposit + const handleMinimalDepositNetChange = (e) => { + setValue('policy_minimal_deposit_net', e.target.value); + setValue( + 'policy_minimal_deposit_percentage', + (e.target.value / values.policy_total_premi) * 100 + ); + }; + const handleMinimalDepositPercentageChange = (e) => { + setValue('policy_minimal_deposit_percentage', e.target.value); + setValue('policy_minimal_deposit_net', (values.policy_total_premi * e.target.value) / 100); + }; + // Only Handle on Change Minimal Alert + const handleMinimalAlertNetChange = (e) => { + setValue('policy_minimal_alert_net', e.target.value); + setValue('policy_minimal_alert_percentage', (e.target.value / values.policy_total_premi) * 100); + }; + const handleMinimalAlertPercentageChange = (e) => { + setValue('policy_minimal_alert_percentage', e.target.value); + setValue('policy_minimal_alert_net', (values.policy_total_premi * e.target.value) / 100); + }; + // Only Handle on Change Minimum Stop Service + const handleStopServiceNetChange = (e) => { + setValue('policy_stop_service_net', e.target.value); + setValue('policy_stop_service_percentage', (e.target.value / values.policy_total_premi) * 100); + }; + const handleStopServicePercentageChange = (e) => { + setValue('policy_stop_service_percentage', e.target.value); + setValue('policy_stop_service_net', (values.policy_total_premi * e.target.value) / 100); + }; + + const linking_rules_checkbox_name = 'linking_rules'; + const linking_tools = [ + { + value: 'nric', + label: 'No. KTP', + }, + { + value: 'nik', + label: 'Nomor Induk Karyawan (NIK)', + }, + { + value: 'member_id', + label: 'Member ID', + }, + { + value: 'policy_code', + label: 'Policy Number', + }, + { + value: 'phone', + label: 'Nomor Telepon', + }, + { + value: 'email', + label: 'E-Mail', + }, + { + value: 'name', + label: 'Nama Lengkap', + }, + { + value: 'dob', + label: 'Tanggal Lahir', + }, + ]; + + const types = [ + { + value: 'corporate', + label: 'Corporate', + }, + { + value: 'subcorporate', + label: 'Sub Corporate', + }, + ]; + + const options = [ + { + label: 'Something', + id: 'Something', + }, + { + label: 'Syalalalal', + id: 'Syalalalal', + }, + { + label: 'Lilili', + id: 'Lilili', + }, + ]; + const [isDisabled, setIsDisabled] = useState(true); + const handleTypeChange = (event: SelectChangeEvent) => { + setValue('type', event.target.value); + }; + + return ( + + {/* Corporate Detail */} + + + + + + Corporate Profile + + + Corporate Profile* + + + ))} + + + {/* // TODO Use Autocomplete */} + {/* {values.type == 'subcorporate' && ( + + + ))} + + )} */} + Corporate Code* + + + Corporate Name* + + + Payor ID* + + + {/* + + + + + + */} + + + + Welcome Message * + + + + + + + Help Text + + + + + {/*
+ Images + +
*/} +
+
+
+ + {/* + + + + + Company Logo + + + + + Company Active + + + + Company Automatic Linking + + + + + + + + + Linking Rules + + + + + + + + */} + + + + + + + + + {'Save'} + + + + +
+
+ ); +} diff --git a/frontend/client-portal/src/pages/Corporate/Index.tsx b/frontend/client-portal/src/pages/Corporate/Index.tsx new file mode 100644 index 00000000..a2be8bdc --- /dev/null +++ b/frontend/client-portal/src/pages/Corporate/Index.tsx @@ -0,0 +1,142 @@ +/* ---------------------------------- react --------------------------------- */ +import { useState, SyntheticEvent } from 'react'; +/* ---------------------------------- @mui ---------------------------------- */ +import { Box, Tabs, Tab, Container, Grid, Card } from '@mui/material'; +import { styled } from '@mui/material/styles'; +/* ------------------------------- components ------------------------------- */ +import Page from '../../components/Page'; +/* ---------------------------------- hooks --------------------------------- */ +import useSettings from '../../hooks/useSettings'; +import List from './List'; +import ServiceMonitoring from './ServiceMonitoring'; +import UserProfile from './UserProfile'; +import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs'; +import TableMoreMenu from '../../components/table/TableMoreMenu'; + +/* ------------------------------ tabs setting ------------------------------ */ + +/* ---------------------------------- types --------------------------------- */ + +interface TabPanelProps { + children?: React.ReactNode; + index: number; + value: number; +} + +interface StyledTabsProps { + children?: React.ReactNode; + value: number; + onChange: (event: React.SyntheticEvent, newValue: number) => void; +} + +interface StyledTabProps { + label: string; + icon?: string | React.ReactElement; +} + +/* -------------------------------- tab style ------------------------------- */ + +function TabPanel(props: TabPanelProps) { + const { children, value, index, ...other } = props; + + return ( + + ); +} + +function a11yProps(index: number) { + return { + id: `simple-tab-${index}`, + 'aria-controls': `simple-tabpanel-${index}`, + }; +} + +const StyledTabs = styled((props: StyledTabsProps) => )({ + backgroundColor: '#F4F6F8', + padding: '0 24px', + '& .MuiTabs-indicator': { + display: 'flex', + justifyContent: 'space-between', + backgroundColor: 'transparent', + }, + '& .MuiTabs-indicatorSpan': { + maxWidth: 40, + backgroundColor: '#635ee7', + }, +}); + +const StyledTab = styled((props: StyledTabProps) => )( + ({ theme }) => ({ + textTransform: 'none', + fontWeight: 600, + color: theme.palette.grey[600], + marginRight: '5rem', + '&.Mui-selected': { + color: '#212B36', + borderBottom: '2px solid ' + theme.palette.primary.main, + }, + '&:hover': { + color: '#212B36', + opacity: 1, + borderBottom: '2px solid ' + theme.palette.primary.main, + }, + }) +); + +/* -------------------------------------------------------------------------- */ + +export default function Drugs() { + const { themeStretch } = useSettings(); + + const [value, setValue] = useState(0); + const handleChange = (event: SyntheticEvent, newValue: number) => { + setValue(newValue); + }; + + return ( + + + + + + {/* */} + {/* + + + + + + */} + {/* */} + + {/* */} + {/* + + + + + */} + {/* */} + + + + + ); +} diff --git a/frontend/client-portal/src/pages/Corporate/List.tsx b/frontend/client-portal/src/pages/Corporate/List.tsx new file mode 100644 index 00000000..c6fb0a18 --- /dev/null +++ b/frontend/client-portal/src/pages/Corporate/List.tsx @@ -0,0 +1,354 @@ +/* ---------------------------------- @mui ---------------------------------- */ +import { + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TextField, + Stack, + Button, + TableSortLabel, + Typography, + Box, + MenuItem, +} from '@mui/material'; +import { visuallyHidden } from '@mui/utils'; +/* ---------------------------------- axios --------------------------------- */ +// import axios from 'axios'; +import axios from '../../utils/axios'; +/* ---------------------------------- react --------------------------------- */ +import { useContext, useEffect, useState } from 'react'; + +/* -------------------------------- component ------------------------------- */ +import Iconify from '../../components/Iconify'; +import BaseTablePagination from '../../components/BaseTablePagination'; +import TableComponent from '../../components/Table'; + +/* ---------------------------------- hooks --------------------------------- */ +import useMap from '../../hooks/useMap'; +/* ---------------------------------- theme --------------------------------- */ +import palette from '../../theme/palette'; +import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; +import { HeadCell, Order, PaginationTableProps } from '../../@types/table'; +import { useSearchParams, useNavigate, Link } from 'react-router-dom'; +import TableMoreMenu from '../../components/table/TableMoreMenu'; +import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; +import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; + + +/* ---------------------------------- types --------------------------------- */ + +// type PaginationTableProps = { +// current_page: number; +// from: number; +// last_page: number; +// links: []; +// path: string; +// per_page: number; +// to: number; +// total: number; +// }; + +// type DataTableProps = { +// fullName: string; +// memberId: string; +// service: string; +// start_date: string; +// end_date: string; +// status: boolean | number; +// }; + +// /* -------------------------------------------------------------------------- */ + +// /* -------------------------- enchanced table head -------------------------- */ + +// type Order = 'asc' | 'desc'; + +// interface HeadCell { +// id: string; +// label: string; +// } + +// const headCells: readonly HeadCell[] = [ +// { +// id: 'name', +// label: 'Name', +// }, +// { +// id: 'member_id', +// label: 'Member ID', +// }, +// { +// id: 'service', +// label: 'Service', +// }, +// { +// id: 'start_date', +// label: 'Start Date', +// }, +// { +// id: 'end_date', +// label: 'End Date', +// }, +// { +// id: 'status', +// label: 'Status', +// }, +// ]; + +// interface EnhancedTableProps { +// onRequestSort: (event: React.MouseEvent, property: string) => void; +// order: Order; +// orderBy: string; +// } + +// function EnhancedTableHead(props: EnhancedTableProps) { +// const { order, orderBy, onRequestSort } = props; +// const createSortHandler = (property: string) => (event: React.MouseEvent) => { +// onRequestSort(event, property); +// }; + +// return ( +// +// +// No +// {headCells.map((headCell) => ( +// +// +// {headCell.label} +// {orderBy === headCell.id ? ( +// +// {order === 'desc' ? 'sorted descending' : 'sorted ascending'} +// +// ) : null} +// +// +// ))} +// +// +// ); +// } + +/* -------------------------------------------------------------------------- */ + +export default function List() { + const navigate = useNavigate(); + + const { corporateValue } = useContext(UserCurrentCorporateContext); + + const [data, setData] = useState([]); + + /* -------------------------------------------------------------------------- */ + /* 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('asc'); + const [orderBy, setOrderBy] = useState('fullName'); + + 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({ + 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 search ----------------------------- */ + const [searchText, setSearchText] = useState(''); + + const handleSearchSubmit = async (event: React.FormEvent) => { + 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: false, + searchText: searchText, + setSearchText: setSearchText, + handleSearchSubmit: handleSearchSubmit, + }; + + /* -------------------------------- headCell -------------------------------- */ + const headCells: HeadCell[] = [ + { + id: 'code', + align: 'left', + label: 'Code', + isSort: true, + }, + { + id: 'name', + align: 'left', + label: 'Name', + isSort: true, + }, + { + id: 'active', + align: 'center', + label: 'Status', + isSort: true, + }, + { + id: 'action', + align: 'center', + label: '', + isSort: true, + }, + + ]; + /* -------------------------------------------------------------------------- */ + + useEffect(() => { + (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(`${corporateValue}/corporate`, { + params: { ...parameters }, + }); + + setData( + response.data.data.map((obj: any) => { + return { + ...obj, + active: + obj.active === 1 ? ( + + Active + + ) : ( + + ), + action: + + navigate(`/corporate/edit`)}> + + Edit + + navigate(`/corporate/view`)}> + + View + + + } /> + , + }; + }) + ); + + 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); + } + + setIsLoading(false); + })(); + }, [appliedParams, searchParams, order, orderBy, setSearchParams, corporateValue]); + + return ( + + + + ); +} diff --git a/frontend/client-portal/src/pages/Corporate/ServiceMonitoring.tsx b/frontend/client-portal/src/pages/Corporate/ServiceMonitoring.tsx new file mode 100644 index 00000000..5fd6e12c --- /dev/null +++ b/frontend/client-portal/src/pages/Corporate/ServiceMonitoring.tsx @@ -0,0 +1,348 @@ +// mui +import { + Box, + Tabs, + Tab, + IconButton, + Container, + Grid, + Card, + Stack, + Typography, +} from '@mui/material'; +import { styled } from '@mui/material/styles'; +import { Favorite } from '@mui/icons-material'; +// components +import Page from '../../components/Page'; +import Iconify from '../../components/Iconify'; +// utils +import useSettings from '../../hooks/useSettings'; +import { useState, SyntheticEvent, useContext, useEffect } from 'react'; +import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; +import { useNavigate, useParams } from 'react-router-dom'; +import axios from '../../utils/axios'; +import { fDate } from '../../utils/formatTime'; + +// sections +// import ListTable from '../../sections/claimreports/ListTable'; +// import ClaimStatusCard from '../../sections/claimreports/ClaimStatusCard'; + +interface TabPanelProps { + children?: React.ReactNode; + index: number; + value: number; +} + +function TabPanel(props: TabPanelProps) { + const { children, value, index, ...other } = props; + + return ( + + ); +} + +function a11yProps(index: number) { + return { + id: `simple-tab-${index}`, + 'aria-controls': `simple-tabpanel-${index}`, + }; +} + +interface StyledTabsProps { + children?: React.ReactNode; + value: number; + onChange: (event: React.SyntheticEvent, newValue: number) => void; +} + +const StyledTabs = styled((props: StyledTabsProps) => )({ + '& .MuiTabs-indicator': { + display: 'flex', + justifyContent: 'center', + backgroundColor: 'transparent', + }, + '& .MuiTabs-indicatorSpan': { + maxWidth: 40, + width: '100%', + backgroundColor: '#635ee7', + }, +}); + +interface StyledTabProps { + label: string; + icon?: string | React.ReactElement; +} + +const StyledTab = styled((props: StyledTabProps) => )( + ({ theme }) => ({ + textTransform: 'none', + fontWeight: 500, + fontSize: theme.typography.pxToRem(20), + color: theme.palette.primary.main, + maxWidth: '100%', + flex: 1, + margin: '0 !important', + '&.Mui-selected': { + color: '#FFF', + backgroundColor: theme.palette.primary.main, + }, + '&:hover': { + backgroundColor: theme.palette.primary.dark, + color: '#FFF', + opacity: 1, + }, + }) +); + +export default function ServiceMonitoring() { + const { themeStretch } = useSettings(); + const navigate = useNavigate(); + + const [value, setValue] = useState(0); + const handleChange = (event: SyntheticEvent, newValue: number) => { + setValue(newValue); + }; + + const [data, setData] = useState({}); + const [corporate, setCorporate] = useState(); + + const { corporateValue } = useContext(UserCurrentCorporateContext); + const { id } = useParams(); + const claimId = '2'; +// console.log('id', id); + + useEffect(() => { + console.log('fetching data...'); + axios + .get('/data/' + id) + .then((response) => { +// console.log('data fetched...', response.data); + setData(response.data); + }) + .catch((error) => { + console.error('error fetching data...', error); + }); + + axios + .get('/corporate-manage/' + corporateValue) + .then((response) => { +// console.log('corporate fetched...', response.data); + setCorporate(response.data); + }) + .catch((error) => { + console.error('error fetching corporate...', error); + }); + }, []); + +// console.log('Data:', data); + const [encounterData, setEncounterData] = useState({}); + + useEffect(() => { +// console.log('fetching encounter data...'); + axios + .get('/claims/${claim_id}/encounters') + .then((response) => { +// console.log('encounter data fetched...', response.data); + setEncounterData(response.data); + }) + .catch((error) => { + console.error('error fetching encounter data...', error); + }); + }, []); + + return ( + + + + navigate('/alarm-center')} + sx={{ marginRight: '10px', color: '#424242' }} + > + + + Service Monitoring + + + Done + + + + {/* Item 1 */} + + + + + + Employee Profiles + + + + + Nama perusahaan + {corporate?.name} + + + Nama Lengkap + {data?.name || 'Loading...'} + + + Tanggal lahir + + {data?.birth_date ? fDate(data?.birth_date) : ''} + + + + Email + {data?.email} + + + No telepon + {data?.phone} + + + + ID Karyawan + 12345678 + + + + + + {/* Item 2 */} + + + + + + Diagnose Summary + + + + Gejala + Nyeri dada + + + Tanda + Sesak Napas + + + Main Diagnose + + J46 Status asthmaticus, Acute severe asthma + + + + Diagnosis pembanding + K21 Gastro-oesophageal reflux disease + + + + + + {/* Item 3 */} + + + + + + Services + + + + + Evakuasi medis + Land Transportation + + + Rumah sakit + Primaya Hospital + + + + Tanggal mulai + 17 Aug 2022 + + + Selesai + 18 Aug 2022 + + + + Daftar layanan + + Inpatient, Medivac (Medical Evacuation) + + + + + + + + + + + } label="Daily Monitoring" {...a11yProps(0)} /> + } + label="Laboratorium Result" + {...a11yProps(1)} + /> + + + + Item One + + + Item Two + + + + + + ); +} diff --git a/frontend/client-portal/src/pages/Corporate/Show.tsx b/frontend/client-portal/src/pages/Corporate/Show.tsx new file mode 100644 index 00000000..3acb3f28 --- /dev/null +++ b/frontend/client-portal/src/pages/Corporate/Show.tsx @@ -0,0 +1,469 @@ +/* ---------------------------------- @mui ---------------------------------- */ +import { + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TextField, + Stack, + Button, + TableSortLabel, + Typography, + Grid, + Box, + Card, + MenuItem, +} from '@mui/material'; +import { visuallyHidden } from '@mui/utils'; +/* ---------------------------------- axios --------------------------------- */ +// import axios from 'axios'; +import axios from '../../utils/axios'; +/* ---------------------------------- react --------------------------------- */ +import { useContext, useEffect, useState } from 'react'; + +/* -------------------------------- component ------------------------------- */ +import Iconify from '../../components/Iconify'; +import BaseTablePagination from '../../components/BaseTablePagination'; +import TableComponent from '../../components/Table'; +import Page from '../../components/Page'; + +/* ---------------------------------- hooks --------------------------------- */ +import useMap from '../../hooks/useMap'; +/* ---------------------------------- theme --------------------------------- */ +import palette from '../../theme/palette'; +import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; +import { HeadCell, Order, PaginationTableProps } from '../../@types/table'; +import { useSearchParams, useNavigate, Link } from 'react-router-dom'; +import TableMoreMenu from '../../components/table/TableMoreMenu'; +import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; +import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; + +/*------------------------------------ icon ----------------------------------- */ +import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; +import UploadImage from '../../components/UploadImage'; +import { Corporate } from '../../@types/corporates'; +import { fDateSuffix } from '../../utils/formatTime'; +import { fSplit } from '../../utils/formatNumber'; + + +/* ---------------------------------- types --------------------------------- */ + +// type PaginationTableProps = { +// current_page: number; +// from: number; +// last_page: number; +// links: []; +// path: string; +// per_page: number; +// to: number; +// total: number; +// }; + +// type DataTableProps = { +// fullName: string; +// memberId: string; +// service: string; +// start_date: string; +// end_date: string; +// status: boolean | number; +// }; + + + +// /* -------------------------------------------------------------------------- */ + +// /* -------------------------- enchanced table head -------------------------- */ + +// type Order = 'asc' | 'desc'; + +// interface HeadCell { +// id: string; +// label: string; +// } + +// const headCells: readonly HeadCell[] = [ +// { +// id: 'name', +// label: 'Name', +// }, +// { +// id: 'member_id', +// label: 'Member ID', +// }, +// { +// id: 'service', +// label: 'Service', +// }, +// { +// id: 'start_date', +// label: 'Start Date', +// }, +// { +// id: 'end_date', +// label: 'End Date', +// }, +// { +// id: 'status', +// label: 'Status', +// }, +// ]; + +// interface EnhancedTableProps { +// onRequestSort: (event: React.MouseEvent, property: string) => void; +// order: Order; +// orderBy: string; +// } + +// function EnhancedTableHead(props: EnhancedTableProps) { +// const { order, orderBy, onRequestSort } = props; +// const createSortHandler = (property: string) => (event: React.MouseEvent) => { +// onRequestSort(event, property); +// }; + +// return ( +// +// +// No +// {headCells.map((headCell) => ( +// +// +// {headCell.label} +// {orderBy === headCell.id ? ( +// +// {order === 'desc' ? 'sorted descending' : 'sorted ascending'} +// +// ) : null} +// +// +// ))} +// +// +// ); +// } + +/* -------------------------------------------------------------------------- */ + +export default function List() { + const navigate = useNavigate(); + + const { corporateValue } = useContext(UserCurrentCorporateContext); + const [currentCorporate, setCurrentCorporate] = useState(null); + + + /* -------------------------------------------------------------------------- */ + /* setting up for the table */ + /* -------------------------------------------------------------------------- */ + const [isLoading, setIsLoading] = useState(true); + + const loadings = { + isLoading: isLoading, + setIsLoading: setIsLoading, + }; + + // useEffect(() => { + // (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(`${corporateValue}/corporate`, { + // params: { ...parameters }, + // }); + // setCurrentCorporate(response.data[0]); + // 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); + // } + + // setIsLoading(false); + // })(); + // }, [appliedParams, searchParams, order, orderBy, setSearchParams, corporateValue]); + useEffect(() => { + axios.get(`${corporateValue}/corporate`) + .then((response) => { + const data = response.data.data[0]; + setCurrentCorporate(data); + }) + .catch((error) => { + console.error('Error fetching corporate data:', error); + // Handle error here + }); + }, [corporateValue]); + + return ( + + + {/* Field 1 */} + + + navigate(`/corporate`)} sx={{ cursor: "pointer" }} /> + Profile Corporate + + + + + + {/* Field 1 */} + + + Corporate Profile + + + + +
+ user-profile +
+
+ + + + Corporate Type + + + {currentCorporate?.type} + + + Corporate Name + + + {currentCorporate?.name} + + + Corporate Code + + + {currentCorporate?.code} + + + Payor ID + + + {currentCorporate?.payor_id} + + + Welcome Messages + + + {currentCorporate?.welcome_message.replace(/<[^>]*>/g, '')} + + + Help Text + + + {currentCorporate?.help_text.replace(/<[^>]*>/g, '')} + + + Linking Rules + + + +
    + {currentCorporate?.linking_rules + .filter(rule => rule) // Menghapus elemen yang kosong atau null + .map((rule, index) => ( +
  • {rule}
  • + ))} +
+
+
+
+
+
+
+
+
+
+ + {/* + + + + Policy Detail + + + + + + Corporate Type + + + {currentCorporate?.type} + + + Corporate Name + + + {currentCorporate?.name} + + + Corporate Code + + + {currentCorporate?.code} + + + Payor ID + + + {currentCorporate?.payor_id} + + + Welcome Messages + + + {currentCorporate?.welcome_message.replace(/<[^>]*>/g, '')} + + + Help Text + + + {currentCorporate?.help_text.replace(/<[^>]*>/g, '')} + + + Linking Rules + + + +
    + {currentCorporate?.linking_rules + .filter(rule => rule) // Menghapus elemen yang kosong atau null + .map((rule, index) => ( +
  • {rule}
  • + ))} +
+
+
+
+
+
+
+
+
*/} + + + + + + Policy Detail + + + + + + Policy Number + + + {currentCorporate?.current_policy?.code} + + + Cooperation Start Date + + + {currentCorporate?.current_policy?.start && fDateSuffix(currentCorporate?.current_policy?.start)} + + + Cooperation End Date + + + {currentCorporate?.current_policy?.end && fDateSuffix(currentCorporate?.current_policy?.end)} + + + Deposit Initial Fund + + + + + + + + + + + + Minimal Depost Policy Level + + + Percentage (%) + + + {currentCorporate?.current_policy?.minimal_deposit_percentage} + + + Net + + + (Rp. {currentCorporate?.current_policy?.minimal_deposit_net && fSplit(currentCorporate?.current_policy?.minimal_deposit_net)}) + + + + Minimal Alert Level + + + Percentage (%) + + + {currentCorporate?.current_policy?.minimal_alert_percentage} + + + Net + + + (Rp. {currentCorporate?.current_policy?.minimal_alert_net && fSplit(currentCorporate?.current_policy?.minimal_alert_net)}) + + + + Minimal Stop Service Level + + + Percentage (%) + + + {currentCorporate?.current_policy?.minimal_stop_service_percentage} + + + Net + + + (Rp. {currentCorporate?.current_policy?.minimal_stop_service_net && fSplit(currentCorporate?.current_policy?.minimal_stop_service_net)}) + + + + + + + + +
+ ); +} diff --git a/frontend/client-portal/src/pages/Corporate/UserProfile.tsx b/frontend/client-portal/src/pages/Corporate/UserProfile.tsx new file mode 100644 index 00000000..0c7a740b --- /dev/null +++ b/frontend/client-portal/src/pages/Corporate/UserProfile.tsx @@ -0,0 +1,85 @@ +// mui +import { IconButton, Container, Grid, Stack, Typography } from '@mui/material'; +// components +import Page from '../../components/Page'; +import Iconify from '../../components/Iconify'; +// utils +import useSettings from '../../hooks/useSettings'; +// section +import CardPersonalInformation from '../../sections/alarm-center/user-profile/CardPersonalInformation'; +import CardFamilyInformation from '../../sections/alarm-center/user-profile/CardFamilyInformation'; +import CardPolicyNumber from '../../sections/alarm-center/user-profile/CardPolicyNumber'; +import CardBenefitSummary from '../../sections/alarm-center/user-profile/CardBenefitSummary'; +import CardClaimHistory from '../../sections/alarm-center/user-profile/CardClaimHistory'; +// react +import { useNavigate, useParams } from 'react-router-dom'; +import ButtonBack from '../../components/ButtonBack'; +import { useEffect, useState, useContext } from 'react'; +import axios from '../../utils/axios'; +import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; + +// ---------------------------------------------------------------------- + +export default function UserProfile() { + const { themeStretch } = useSettings(); + // const navigate = useNavigate(); + const [data, setData] = useState(); + + const { corporateValue } = useContext(UserCurrentCorporateContext); + const { id } = useParams(); + + useEffect(() => { + axios + .get(corporateValue + '/members/' + id) + .then((response) => { + setData(response.data); + }) + .catch((error) => { + console.error(error); + }); + }, []); + +// console.log('data', data); + + return ( + + + + {/* navigate()}> + + */} + + Profil Peserta + + + {/* Row 1 */} + + + {/* Item 1 */} + + + + {/* Item 2 */} + + + + + + {/* Row 2 */} + + + {/* Item 1 */} + + + + {/* Item 2 */} + + + + + + + + + ); +} diff --git a/frontend/client-portal/src/pages/Dashboard/Index.tsx b/frontend/client-portal/src/pages/Dashboard/Index.tsx index 274cbdec..355d4c97 100644 --- a/frontend/client-portal/src/pages/Dashboard/Index.tsx +++ b/frontend/client-portal/src/pages/Dashboard/Index.tsx @@ -177,6 +177,7 @@ export default function Index() { }; const searchs = { + // useSearchs: true, searchText: searchText, setSearchText: setSearchText, handleSearchSubmit: handleSearchSubmit, diff --git a/frontend/client-portal/src/routes/index.tsx b/frontend/client-portal/src/routes/index.tsx index 15325387..e886fcaf 100644 --- a/frontend/client-portal/src/routes/index.tsx +++ b/frontend/client-portal/src/routes/index.tsx @@ -93,6 +93,26 @@ export default function Router() { }, ], }, + { + path: '/claim-submit', + element: ( + + + + + + ), + children: [ + { + element: , + index: true, + }, + { + path: 'dialog-detail', + element: + }, + ], + }, { path: '/claim-report', element: ( @@ -133,6 +153,30 @@ export default function Router() { }, ], }, + { + path: '/corporate', + element: ( + + + + + + ), + children: [ + { + element: , + index: true, + }, + { + path: 'edit', + element: , + }, + { + path: 'view', + element: , + }, + ], + }, { path: '*', element: , @@ -163,4 +207,13 @@ const AlarmCenterUserProfile = Loadable(lazy(() => import('../pages/AlarmCenter/ const ClaimReport = Loadable(lazy(() => import('../pages/ClaimReport/Index'))); const Claims = Loadable(lazy(() => import('../pages/Claims/Index'))); const ClaimShow = Loadable(lazy(() => import('../pages/Claims/Show'))); -const DialogDetailClaim = Loadable(lazy(()=> import('../pages/ClaimReport/DialogDetailClaim'))); \ No newline at end of file +const DialogDetailClaim = Loadable(lazy(()=> import('../pages/ClaimReport/DialogDetailClaim'))); + +// Claim submit +const ClaimSubmit = Loadable(lazy(() => import('../pages/ClaimSubmit/Index'))); + + +// Corporate +const Corporate = Loadable(lazy(() => import('../pages/Corporate/Index'))); +const CorporateEdit = Loadable(lazy(() => import('../pages/Corporate/Form'))); +const CorporateShow = Loadable(lazy(() => import('../pages/Corporate/Show'))); \ No newline at end of file diff --git a/frontend/client-portal/src/sections/claim-submit/CardClaimStatus.tsx b/frontend/client-portal/src/sections/claim-submit/CardClaimStatus.tsx new file mode 100644 index 00000000..5349d055 --- /dev/null +++ b/frontend/client-portal/src/sections/claim-submit/CardClaimStatus.tsx @@ -0,0 +1,102 @@ +// @mui +import { Grid, Card, Typography, Stack } from '@mui/material'; +import { styled } from '@mui/material/styles'; +// theme +import palette from '../../theme/palette'; + +// ---------------------------------------------------------------------- + +interface ClaimStatusType { + name: string; + value: number; + color: string; +} + +interface PropsCardClaimStatus { + data?: ClaimStatusType[]; +} + +// ---------------------------------------------------------------------- + +const RootStyle = styled(Card)(({ theme }) => ({ + boxShadow: 'none', + padding: theme.spacing(2), + color: 'black', + backgroundColor: theme.palette.grey[200], +})); + +// ---------------------------------------------------------------------- + +const defaultData = [ + { name: 'Requested', value: 5, color: palette.dark.primary.dark }, + { name: 'Approval', value: 1, color: palette.dark.warning.dark }, + { name: 'Disbrusment', value: 0, color: palette.dark.success.dark }, + { name: 'Rejected', value: 3, color: palette.dark.error.dark }, +]; + +// ---------------------------------------------------------------------- + +export default function CardClaimStatus({ data }: PropsCardClaimStatus) { + return ( + + + Claim Status + + + {data + ? data.map(({ name, value, color }: ClaimStatusType, key) => ( + + + + {name} + + + {value} + + + Cases + + + + )) + : defaultData.map(({ name, value, color }: ClaimStatusType, key) => ( + + + + {name} + + + {value} + + + Cases + + + + ))} + + + ); +} diff --git a/frontend/client-portal/src/sections/dashboard/DialogRequestLog.tsx b/frontend/client-portal/src/sections/dashboard/DialogRequestLog.tsx index be4fb691..d9267492 100644 --- a/frontend/client-portal/src/sections/dashboard/DialogRequestLog.tsx +++ b/frontend/client-portal/src/sections/dashboard/DialogRequestLog.tsx @@ -113,7 +113,7 @@ const DialogRequestLog = ({ openDialog, setOpenDialog, data }: MuiDialogProps) = const [submitLoading, setSubmitLoading] = useState(false); function submitRequest() { setSubmitLoading(true); - + console.log(data.id); const formData = makeFormData({ member_id: data.id, result_files: fileHasilPenunjangs, diff --git a/frontend/client-portal/src/utils/formatTime.ts b/frontend/client-portal/src/utils/formatTime.ts index 7fef0e22..a8ecb956 100644 --- a/frontend/client-portal/src/utils/formatTime.ts +++ b/frontend/client-portal/src/utils/formatTime.ts @@ -19,6 +19,10 @@ export function fDateTimeSuffix(date: Date | string | number) { return format(new Date(date), 'dd/MM/yyyy hh:mm p'); } +export function fDateSuffix(date: Date | string | number) { + return format(new Date(date), 'dd MMM yyyy'); +} + export function fToNow(date: Date | string | number) { return formatDistanceToNow(new Date(date), { addSuffix: true, diff --git a/frontend/dashboard/src/components/table/Index.ts b/frontend/dashboard/src/components/table/Index.ts new file mode 100644 index 00000000..8b4b0f88 --- /dev/null +++ b/frontend/dashboard/src/components/table/Index.ts @@ -0,0 +1 @@ +export { default as TableMoreMenu } from './TableMoreMenu'; \ No newline at end of file diff --git a/frontend/dashboard/src/components/table/TableMoreMenu.tsx b/frontend/dashboard/src/components/table/TableMoreMenu.tsx new file mode 100644 index 00000000..6fe3f43e --- /dev/null +++ b/frontend/dashboard/src/components/table/TableMoreMenu.tsx @@ -0,0 +1,60 @@ +import { useEffect, useState } from 'react'; +// @mui +import { IconButton } from '@mui/material'; +// +import Iconify from '../Iconify'; +import MenuPopover from '../MenuPopover'; + +// ---------------------------------------------------------------------- + +type Props = { + actions: React.ReactNode; + disableRipple?: boolean; +}; + +export default function TableMoreMenu({ actions, disableRipple }: Props) { + const [open, setOpen] = useState(null); + + // Close menu popover + useEffect(() => { + setOpen(null); + }, [actions]) + + const handleOpen = (event: React.MouseEvent) => { + setOpen(event.currentTarget); + }; + + const handleClose = () => { + setOpen(null); + }; + + return ( + <> + + + + + + {actions} + +     +  ); +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/Corporates/Benefit/Index.tsx b/frontend/dashboard/src/pages/Corporates/Benefit/Index.tsx index 21e25e16..54cac928 100644 --- a/frontend/dashboard/src/pages/Corporates/Benefit/Index.tsx +++ b/frontend/dashboard/src/pages/Corporates/Benefit/Index.tsx @@ -35,11 +35,11 @@ export default function Divisions() { }, { name: corporate?.name ?? '-', - href: '/corporate/' + corporate_id, + href: '/corporates/' + corporate_id, }, { name: 'Benefit', - href: '/corporate/' + corporate_id + '/benefits', + href: '/corporates/' + corporate_id + '/benefits', }, ]} /> diff --git a/frontend/dashboard/src/pages/Corporates/ClaimHistory/Index.tsx b/frontend/dashboard/src/pages/Corporates/ClaimHistory/Index.tsx index 6fe66cdf..e30db1cd 100644 --- a/frontend/dashboard/src/pages/Corporates/ClaimHistory/Index.tsx +++ b/frontend/dashboard/src/pages/Corporates/ClaimHistory/Index.tsx @@ -33,11 +33,11 @@ export default function Divisions() { }, { name: corporate?.name ?? '-', - href: '/corporate/' + corporate_id, + href: '/corporates/' + corporate_id, }, { name: 'Claim History', - href: '/corporate/' + corporate_id + '/claim-histories', + href: '/corporates/' + corporate_id + '/claim-histories', }, ]} /> diff --git a/frontend/dashboard/src/pages/Corporates/CorporatePlan/Index.tsx b/frontend/dashboard/src/pages/Corporates/CorporatePlan/Index.tsx index ddc01dbd..247d941e 100644 --- a/frontend/dashboard/src/pages/Corporates/CorporatePlan/Index.tsx +++ b/frontend/dashboard/src/pages/Corporates/CorporatePlan/Index.tsx @@ -32,11 +32,11 @@ export default function Divisions() { }, { name: corporate?.name ?? '-', - href: '/corporate/' + corporate_id, + href: '/corporates/' + corporate_id, }, { name: 'Corporate Plan', - href: '/corporate/' + corporate_id + '/corporate-plans', + href: '/corporates/' + corporate_id + '/corporate-plans', }, ]} /> diff --git a/frontend/dashboard/src/pages/Corporates/CorporateTabNavigations.tsx b/frontend/dashboard/src/pages/Corporates/CorporateTabNavigations.tsx index 2b1d4860..4cfffe6d 100644 --- a/frontend/dashboard/src/pages/Corporates/CorporateTabNavigations.tsx +++ b/frontend/dashboard/src/pages/Corporates/CorporateTabNavigations.tsx @@ -89,7 +89,7 @@ export default function CorporateTabNavigations({ position }: Props) { { - navigate('/corporate/' + corporate_id + '/' + mainTabItems[index].path); + navigate('/corporates/' + corporate_id + '/' + mainTabItems[index].path); }} label={tabItem.label} /> diff --git a/frontend/dashboard/src/pages/Corporates/DiagnosisExclusion/Index.tsx b/frontend/dashboard/src/pages/Corporates/DiagnosisExclusion/Index.tsx index f07e76ff..05a3808b 100644 --- a/frontend/dashboard/src/pages/Corporates/DiagnosisExclusion/Index.tsx +++ b/frontend/dashboard/src/pages/Corporates/DiagnosisExclusion/Index.tsx @@ -36,11 +36,11 @@ export default function Divisions() { }, { name: corporate?.name ?? '-', - href: '/corporate/' + corporate_id, + href: '/corporates/' + corporate_id, }, { name: 'Diagnosis Exclusion', - href: '/corporate/' + corporate_id + '/diagnosis-exclusions', + href: '/corporates/' + corporate_id + '/diagnosis-exclusions', }, ]} /> diff --git a/frontend/dashboard/src/pages/Corporates/Division/Index.tsx b/frontend/dashboard/src/pages/Corporates/Division/Index.tsx index 43361b05..5de7ce4e 100644 --- a/frontend/dashboard/src/pages/Corporates/Division/Index.tsx +++ b/frontend/dashboard/src/pages/Corporates/Division/Index.tsx @@ -32,15 +32,15 @@ export default function Divisions() { links={[ { name: 'Corporates', - href: '/corporate', + href: '/corporates', }, { name: corporate?.name ?? '-', - href: '/corporate/' + corporate_id, + href: '/corporates/' + corporate_id, }, { name: 'Division', - href: '/corporate/' + corporate_id + '/divisions', + href: '/corporates/' + corporate_id + '/divisions', }, ]} /> diff --git a/frontend/dashboard/src/pages/Corporates/Form.tsx b/frontend/dashboard/src/pages/Corporates/Form.tsx index 37e18366..b739a98c 100644 --- a/frontend/dashboard/src/pages/Corporates/Form.tsx +++ b/frontend/dashboard/src/pages/Corporates/Form.tsx @@ -10,14 +10,19 @@ import { styled } from '@mui/material/styles'; import { LoadingButton } from '@mui/lab'; import { Box, + Button, Card, FormControl, + FormControlLabel, FormHelperText, + FormLabel, Grid, InputLabel, Menu, MenuItem, OutlinedInput, + Radio, + RadioGroup, Select, SelectChangeEvent, Stack, @@ -44,6 +49,8 @@ import { fCurrency } from '../../utils/formatNumber'; import RHFAutocomplete from '../../components/hook-form/RHFAutocomplete'; import UploadImage from '../../components/UploadImage'; import { fPostFormat } from '@/utils/formatTime'; +import AddIcon from '@mui/icons-material/Add'; +import Link from '@/theme/overrides/Link'; const LabelStyle = styled(Typography)(({ theme }) => ({ ...theme.typography.subtitle2, @@ -117,12 +124,14 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) { NewCorporateSchema = Yup.object().shape({ isEdited: Yup.boolean(), name: Yup.string().required('Name is required'), + code: Yup.string() .required('Corporate Code is required') .test('unique-code', 'Code must be unique', async function (value) { const existingCodes = await getExistingCodes(); return !existingCodes.includes(value); - }), + }), + // payor_id: Yup.string().required('Payor is required'), active: Yup.boolean().required('Corporate Status is required'), type: Yup.string().required('Type is required'), welcome_message: Yup.string().required('Welcome Message is required'), @@ -487,9 +496,10 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) { - Corporate Profile + Corporate Profile + Corporate Profile* )} + Corporate Code* + Corporate Name* + Payor ID* {isEdit && ( @@ -534,15 +547,15 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) { )} - - Welcome Message + + Welcome Message * - + - - Help Text + + Help Text * @@ -614,27 +627,30 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) { {/* Policy Detail */} - Policy Detail + Policy Detail + Policy Number* {!currentCorporate?.id && ( Will be generated if empty )} - {/* Minimal Deposit Policy Level */} - + Tanggal Mulai Kerjasama* + - + Tanggal Akhir Kerjasama* + + Deposit Intial Fund* - + Minimal Deposit Policy Level @@ -667,7 +683,7 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) { - + Minimal Alert Level @@ -691,7 +707,7 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) { - + Stop Service Level @@ -716,6 +732,82 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) { )} + {/* Type contrack */} + + + + + Tipe Pembayaran + + + + + + + + #1 + + + + + Tanggal Mulai Kontrak* + + + Tanggal Akhir Kontrak* + + + + + + + + + + + + + Tipe Pembayaran + + } label="Deposit" /> + } label="Hutang" /> + } label="Penagihan Hutang" /> + + + + + + + + Save + + + + + + diff --git a/frontend/dashboard/src/pages/Corporates/History.tsx b/frontend/dashboard/src/pages/Corporates/History.tsx index f657b5ab..09c0cdf1 100644 --- a/frontend/dashboard/src/pages/Corporates/History.tsx +++ b/frontend/dashboard/src/pages/Corporates/History.tsx @@ -121,11 +121,11 @@ export default function CustomizedAccordions() { }, { name: corporate?.name ?? '-', - href: '/corporate/' + corporate_id, + href: '/corporates/' + corporate_id, }, { name: 'Audittrail Corporate', - href: '/corporate/' + corporate_id + '/plans', + href: '/corporates/' + corporate_id + '/plans', }, ]} /> @@ -157,12 +157,13 @@ export default function CustomizedAccordions() { } switch (key) { case 'welcome_message': - renderedValue = item.new_values[key].replace(/<[^>]*>/g, ''); - value = value.replace(/<[^>]*>/g, ''); + // renderedValue = item.new_values[key].replace(/<[^>]*>/g, ''); + renderedValue = item.new_values[key]; + value = value; break; case 'help_text': - renderedValue = item.new_values[key].replace(/<[^>]*>/g, ''); - value = value.replace(/<[^>]*>/g, ''); + renderedValue = item.new_values[key]; + value = value; break; case 'active': renderedValue = item.new_values[key] == 1 ? 'Active' : 'Inactive'; diff --git a/frontend/dashboard/src/pages/Corporates/Hospital/Index.tsx b/frontend/dashboard/src/pages/Corporates/Hospital/Index.tsx index ecea90a4..d5fa1fa3 100644 --- a/frontend/dashboard/src/pages/Corporates/Hospital/Index.tsx +++ b/frontend/dashboard/src/pages/Corporates/Hospital/Index.tsx @@ -34,11 +34,11 @@ export default function Divisions() { }, { name: corporate?.name ?? '-', - href: '/corporate/' + corporate_id, + href: '/corporates/' + corporate_id, }, { name: 'Hospitals', - href: '/corporate/' + corporate_id + '/hospitals', + href: '/corporates/' + corporate_id + '/hospitals', }, ]} /> diff --git a/frontend/dashboard/src/pages/Corporates/Index.tsx b/frontend/dashboard/src/pages/Corporates/Index.tsx index 5253961b..689a144b 100644 --- a/frontend/dashboard/src/pages/Corporates/Index.tsx +++ b/frontend/dashboard/src/pages/Corporates/Index.tsx @@ -30,6 +30,9 @@ import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; import PublishIcon from '@mui/icons-material/Publish'; import AddIcon from '@mui/icons-material/Add'; import HistoryIcon from '@mui/icons-material/History'; +import MoreVertIcon from '@mui/icons-material/MoreVert'; +import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; +import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined'; // hooks import useSettings from '../../hooks/useSettings'; @@ -37,7 +40,7 @@ import useSettings from '../../hooks/useSettings'; import Page from '../../components/Page'; import axios from '../../utils/axios'; import useAuth from '../../hooks/useAuth'; -import { Link, NavLink as RouterLink, useSearchParams } from 'react-router-dom'; +import { Link, NavLink as RouterLink, useNavigate, useSearchParams } from 'react-router-dom'; import React, { ChangeEvent, useEffect, useRef, useState } from 'react'; import { Theme, useTheme } from '@mui/material/styles'; import { Corporate } from '../../@types/corporates'; @@ -47,10 +50,18 @@ import BasePagination from '../../components/BasePagination'; import { fCurrency } from '../../utils/formatNumber'; import { enqueueSnackbar } from 'notistack'; import { fDate } from '@/utils/formatTime'; +import Popover from '@mui/material/Popover'; +import PopupState, { bindTrigger, bindPopover } from 'material-ui-popup-state'; + +import ButtonStyles from '../../theme/overrides/Button'; +import TableMoreMenu from '@/components/table/TableMoreMenu'; +import Iconify from '@/components/Iconify'; + export default function Corporates() { const { themeStretch } = useSettings(); const [searchParams, setSearchParams] = useSearchParams(); + const navigate = useNavigate() // Called on every row to map the data to the columns function createData(corporate: Corporate): Corporate { @@ -181,7 +192,8 @@ export default function Corporates() { ref={searchInput} label="Search" variant="outlined" - fullWidth + // fullWidth + style={{ width: '85%' }} onChange={handleSearchChange} value={searchText} /> @@ -246,8 +258,8 @@ export default function Corporates() { Import */} - {/* */} @@ -265,6 +277,7 @@ export default function Corporates() { function Row(props: { row: ReturnType }) { const { row } = props; const [open, setOpen] = React.useState(false); + const navigate = useNavigate() const handleActivate = (model: any, status: string) => { axios @@ -295,11 +308,11 @@ export default function Corporates() { return ( - *': { borderBottom: 'unset' } }}> + - setOpen(!open)}> + {/* setOpen(!open)}> {open ? : } - + */} {row.code} {row.name} @@ -330,7 +343,7 @@ export default function Corporates() { )} - + {/*