Merge branch 'staging' of itcorp.primaya.id:rajif/aso into staging
This commit is contained in:
@@ -3,50 +3,26 @@
|
||||
namespace Modules\Client\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Member;
|
||||
use App\Services\CorporateMemberService;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Modules\Client\Transformers\MemberResources;
|
||||
use Modules\Client\Transformers\Dashboard\MemberResources;
|
||||
|
||||
class CorporateMemberController extends Controller
|
||||
{
|
||||
public function __construct(public CorporateMemberService $corporateMemberService)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index(Request $request, $corporate_id)
|
||||
{
|
||||
$limit = $request->has('per_page') ? $request->per_page : 10;
|
||||
$members = $this->corporateMemberService->getAllDashboardMembers($corporate_id, $request);
|
||||
|
||||
$members = Member::query()
|
||||
->whereHas('employeds', function ($corporateEmployee) use ($corporate_id) {
|
||||
$corporateEmployee->where('corporate_id', $corporate_id);
|
||||
})->when($request->input('search'), function ($query, $search) {
|
||||
$query->where('member_id', 'like', "%" . $search . "%")
|
||||
->orWhere('name', 'like', "%" . $search . "%");
|
||||
});
|
||||
|
||||
if ($request->input('claimMember') === 'false') {
|
||||
$members = $members->when($request->input('division'), function ($division, $division_id) {
|
||||
$division->whereHas('division', function ($corporateEmployee) use ($division_id) {
|
||||
$corporateEmployee->where('division_id', $division_id);
|
||||
});
|
||||
})->when($request->has('orderBy'), function ($query) use ($request) {
|
||||
$query->orderBy($request->orderBy, $request->order);
|
||||
});
|
||||
}
|
||||
// else {
|
||||
// $members = $members->get();
|
||||
|
||||
// return response()->json(MemberResources::collection($members));
|
||||
// }
|
||||
$members->with('currentPlan');
|
||||
$members->withSum('claims', 'total_claim');
|
||||
|
||||
$members = $members->paginate($limit);
|
||||
// return $members;
|
||||
|
||||
return response()->json(Helper::paginateResources(MemberResources::collection($members)));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
namespace Modules\Client\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Modules\Client\Transformers\DashboardResources;
|
||||
use Modules\Client\Transformers\Dashboard\LimitResources;
|
||||
|
||||
class CorporatePolicyController extends Controller
|
||||
{
|
||||
@@ -16,14 +17,13 @@ class CorporatePolicyController extends Controller
|
||||
*/
|
||||
public function index(Request $request, $corporate_id)
|
||||
{
|
||||
$user = Auth::user();
|
||||
$currentCorporate = $user->managedCorporates()
|
||||
$currentCorporate = Auth::user()->managedCorporates()
|
||||
->with(['currentPolicy', 'employees'])
|
||||
->find($corporate_id);
|
||||
|
||||
$data = DashboardResources::make($currentCorporate);
|
||||
$data = LimitResources::make($currentCorporate);
|
||||
|
||||
return response()->json($data);
|
||||
return Helper::responseJson($data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Client\Transformers;
|
||||
namespace Modules\Client\Transformers\Dashboard;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class DashboardResources extends JsonResource
|
||||
class LimitResources extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
@@ -22,17 +21,15 @@ class DashboardResources extends JsonResource
|
||||
$lockPercentage = (int)$this->currentPolicy->minimal_stop_service_percentage;
|
||||
|
||||
return [
|
||||
'policy' => [
|
||||
'myLimit' => [
|
||||
'balance' => $myLimitBalance,
|
||||
'total' => $myLimitTotal,
|
||||
'percentage' => $myLimitTotal ? (($myLimitBalance / $myLimitTotal) * 100) : 0,
|
||||
],
|
||||
'lockLimit' => [
|
||||
'balance' => $lockBalance,
|
||||
'percentage' => $lockPercentage
|
||||
]
|
||||
'myLimit' => [
|
||||
'balance' => $myLimitBalance,
|
||||
'total' => $myLimitTotal,
|
||||
'percentage' => $myLimitTotal ? round(($myLimitBalance / $myLimitTotal) * 100, 2) : 0,
|
||||
],
|
||||
'lockLimit' => [
|
||||
'balance' => $lockBalance,
|
||||
'percentage' => $lockPercentage
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Client\Transformers;
|
||||
namespace Modules\Client\Transformers\Dashboard;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
@@ -18,15 +18,13 @@ class MemberResources extends JsonResource
|
||||
'id' => $this->id,
|
||||
'memberId' => $this->member_id,
|
||||
'fullName' => $this->full_name,
|
||||
$this->mergeWhen($request->input('claimMember') === 'false', [
|
||||
'division' => $this->division->name ?? '',
|
||||
'status' => $this->active
|
||||
]),
|
||||
'division' => $this->division_name ?? '',
|
||||
'limit' => [
|
||||
'current' => $this->claims_sum_total_claim,
|
||||
'total' => $this->currentPlan->limit_rules ?? 0,
|
||||
'percentage' => (!empty($this->currentPlan->limit_rules ?? 0)) ? (($this->claims_sum_total_claim / $this->currentPlan->limit_rules) * 100) : 0
|
||||
],
|
||||
'status' => $this->active,
|
||||
];
|
||||
}
|
||||
}
|
||||
40
app/Builders/MemberBuilder.php
Normal file
40
app/Builders/MemberBuilder.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class MemberBuilder extends Builder
|
||||
{
|
||||
public function filter(array $filters): static
|
||||
{
|
||||
return $this->when($filters['search'] ?? false, function (MemberBuilder $query, $search) {
|
||||
$query->where('member_id', 'like', "%" . $search . "%")
|
||||
->orWhere('payor_id', 'like', "%" . $search . "%")
|
||||
->orWhere('email', 'like', "%" . $search . "%")
|
||||
->orWhereHas('person', function ($query) use ($search) {
|
||||
$query->where('name', 'like', "%" . $search . "%");
|
||||
$query->orWhere('phone', 'like', "%" . $search . "%");
|
||||
})
|
||||
->orWhereHas('currentPlan', function ($query) use ($search) {
|
||||
$query->where('code', 'like', "%" . $search . "%");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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')
|
||||
};
|
||||
}
|
||||
|
||||
public function joinCorporateDivisions(string $value = 'join'): static
|
||||
{
|
||||
return match ($value) {
|
||||
'join' => $this->join('corporate_divisions', 'corporate_employees.division_id', '=', 'corporate_divisions.id'),
|
||||
'left' => $this->leftJoin('corporate_divisions', 'corporate_employees.division_id', '=', 'corporate_divisions.id')
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Builders\MemberBuilder;
|
||||
use App\Traits\Blameable;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
@@ -73,6 +75,19 @@ class Member extends Model
|
||||
'deleted_by',
|
||||
];
|
||||
|
||||
public static function query(): MemberBuilder
|
||||
{
|
||||
return parent::query();
|
||||
}
|
||||
|
||||
public function newEloquentBuilder($query): MemberBuilder
|
||||
{
|
||||
return new MemberBuilder($query);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* relationship */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
public function claims()
|
||||
{
|
||||
return $this->hasMany(Claim::class, 'member_id', 'id');
|
||||
@@ -111,7 +126,7 @@ class Member extends Model
|
||||
{
|
||||
// return $this->belongsToMany(Corporate::class, 'corporate_employees', 'corporate_id', 'member_id')
|
||||
// // ->withPivot([
|
||||
// // 'branch_code',
|
||||
// // 'branch_code',
|
||||
// // 'divison_id',
|
||||
// // 'nik',
|
||||
// // 'status',
|
||||
@@ -167,75 +182,69 @@ class Member extends Model
|
||||
->where('member_policies.end', '>', now());
|
||||
}
|
||||
|
||||
public function getAgeAttribute()
|
||||
{
|
||||
if ($this->birth_date) {
|
||||
return Carbon::parse($this->birth_date)->diffInYears(now());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function getFullNameAttribute()
|
||||
{
|
||||
if (!$this->person) {
|
||||
return null;
|
||||
}
|
||||
$arr = [];
|
||||
if (!empty($this->person->name_prefix)) {
|
||||
$arr[] = $this->person->name_prefix;
|
||||
}
|
||||
$arr[] = $this->person->name;
|
||||
if (!empty($this->person->name_suffix)) {
|
||||
$arr[] = $this->person->name_suffix;
|
||||
}
|
||||
|
||||
return implode(' ', $arr);
|
||||
}
|
||||
|
||||
public function getGenderCodeAttribute()
|
||||
{
|
||||
return $this->gender ? ($this->gender == 'female' ? 'F' : 'M') : $this->gender;
|
||||
}
|
||||
|
||||
public function getNameAttribute()
|
||||
{
|
||||
return $this->person->name ?? ($this->name ?? null);
|
||||
}
|
||||
|
||||
public function getBirthDateAttribute()
|
||||
{
|
||||
$date = $this->person->birth_date ?? ($this->birth_date ?? null);
|
||||
return !empty($date) ? Carbon::parse($date)->format('Y-m-d') : null;
|
||||
}
|
||||
|
||||
public function getGenderAttribute()
|
||||
{
|
||||
return $this->person->gender ?? null;
|
||||
}
|
||||
|
||||
public function scopeFilter($query, array $filters)
|
||||
{
|
||||
$query->when($filters['search'] ?? false, function ($query, $search) {
|
||||
return $query
|
||||
->where('member_id', 'like', "%" . $search . "%")
|
||||
->orWhere('payor_id', 'like', "%" . $search . "%")
|
||||
->orWhere('email', 'like', "%" . $search . "%")
|
||||
->orWhereHas('person', function ($query) use ($search) {
|
||||
$query->where('name', 'like', "%" . $search . "%");
|
||||
$query->orWhere('phone', 'like', "%" . $search . "%");
|
||||
})
|
||||
->orWhereHas('currentPlan', function ($query) use ($search) {
|
||||
$query->where('code', 'like', "%" . $search . "%");
|
||||
});
|
||||
// ->orWhereHas('corporatePlan', function ($query) use ($search) {
|
||||
// $query->where('code', 'like', "%" . $search . "%");
|
||||
// });
|
||||
});
|
||||
}
|
||||
|
||||
public function division()
|
||||
{
|
||||
return $this->hasOneThrough(CorporateDivision::class, CorporateEmployee::class, 'member_id', 'id', 'id', 'division_id');
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Accessors & Mutators */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
protected function age(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => Carbon::parse($this->birth_date)->diffInYears(now())
|
||||
);
|
||||
}
|
||||
|
||||
protected function fullName(): Attribute
|
||||
{
|
||||
$arr = [];
|
||||
|
||||
if (!empty($this->person->name_prefix)) {
|
||||
$arr[] = $this->person->name_prefix;
|
||||
}
|
||||
|
||||
$arr[] = $this->person->name;
|
||||
|
||||
if (!empty($this->person->name_suffix)) {
|
||||
$arr[] = $this->person->name_suffix;
|
||||
}
|
||||
|
||||
return Attribute::make(
|
||||
get: fn () => !$this->person ? null : implode(' ', $arr)
|
||||
);
|
||||
}
|
||||
|
||||
protected function genderCode(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->gender ? ($this->gender == 'female' ? 'F' : 'M') : $this->gender
|
||||
);
|
||||
}
|
||||
|
||||
protected function name(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->person->name ?? ($this->name ?? null)
|
||||
);
|
||||
}
|
||||
|
||||
protected function birthDate(): Attribute
|
||||
{
|
||||
$date = $this->person->birth_date ?? ($this->birth_date ?? null);
|
||||
|
||||
return Attribute::make(
|
||||
get: fn () => !empty($date) ? Carbon::parse($date)->format('Y-m-d') : null
|
||||
);
|
||||
}
|
||||
|
||||
protected function gender(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->person->gender ?? null
|
||||
);
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
}
|
||||
|
||||
49
app/Services/CorporateMemberService.php
Normal file
49
app/Services/CorporateMemberService.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Member;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CorporateMemberService
|
||||
{
|
||||
public function getAllDashboardMembers(int $corporateId, Request $request)
|
||||
{
|
||||
$limit = $request->has('perPage') ? $request->input('perPage') : 10;
|
||||
|
||||
return Member::query()
|
||||
->joinCorporateEmployees('left')
|
||||
->joinCorporateDivisions('left')
|
||||
->with('currentPlan')
|
||||
->withSum('claims', 'total_claim')
|
||||
->whereHas('employeds', function (Builder $corporateEmployee) use ($corporateId) {
|
||||
$corporateEmployee->where('corporate_id', $corporateId);
|
||||
})
|
||||
->when($request->input('search'), function (Builder $query, $search) {
|
||||
$query->where('member_id', 'like', "%" . $search . "%")
|
||||
->orWhere('name', 'like', "%" . $search . "%");
|
||||
})
|
||||
->when($request->input('division'), function (Builder $division, $division_id) {
|
||||
$division->whereHas('division', function ($corporateEmployee) use ($division_id) {
|
||||
$corporateEmployee->where('division_id', $division_id);
|
||||
});
|
||||
})
|
||||
->when($request->has('orderBy'), function (Builder $query) use ($request) {
|
||||
$orderBy = match ($request->orderBy) {
|
||||
'memberId' => 'member_id',
|
||||
'fullName' => 'name',
|
||||
'status' => 'active',
|
||||
default => ''
|
||||
};
|
||||
|
||||
if (in_array($orderBy, ['member_id', 'name', 'active'])) {
|
||||
$query->getQuery()->orderBy($orderBy, $request->order);
|
||||
} elseif ($request->orderBy === 'division') {
|
||||
$query->getQuery()->orderBy('corporate_divisions.name', $request->order);
|
||||
}
|
||||
})
|
||||
->select(['members.id', 'members.person_id', 'members.member_id', 'members.name', 'members.name_prefix', 'members.name_suffix', 'corporate_divisions.name AS division_name', 'members.active'])
|
||||
->paginate($limit);
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ return [
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'strict' => env('DB_STRICT', true),
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
@@ -145,7 +145,7 @@ return [
|
||||
|
||||
'options' => [
|
||||
'cluster' => env('REDIS_CLUSTER', 'redis'),
|
||||
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
|
||||
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_') . '_database_'),
|
||||
],
|
||||
|
||||
'default' => [
|
||||
|
||||
@@ -37,80 +37,81 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@date-io/date-fns": "^2.15.0",
|
||||
"@emotion/cache": "^11.10.3",
|
||||
"@emotion/react": "^11.10.0",
|
||||
"@emotion/styled": "^11.10.0",
|
||||
"@hookform/resolvers": "^2.9.7",
|
||||
"@date-io/date-fns": "^2.16.0",
|
||||
"@emotion/cache": "^11.10.5",
|
||||
"@emotion/react": "^11.10.6",
|
||||
"@emotion/styled": "^11.10.6",
|
||||
"@hookform/resolvers": "^2.9.11",
|
||||
"@iconify/react": "^3.2.2",
|
||||
"@mui/icons-material": "^5.10.2",
|
||||
"@mui/icons-material": "^5.11.11",
|
||||
"@mui/lab": "5.0.0-alpha.80",
|
||||
"@mui/material": "^5.10.2",
|
||||
"@mui/system": "^5.10.2",
|
||||
"@mui/utils": "^5.10.16",
|
||||
"@mui/x-data-grid": "^5.16.0",
|
||||
"@mui/material": "^5.11.14",
|
||||
"@mui/system": "^5.11.14",
|
||||
"@mui/utils": "^5.11.13",
|
||||
"@mui/x-data-grid": "^5.17.26",
|
||||
"@mui/x-date-pickers": "5.0.0-beta.2",
|
||||
"@vitejs/plugin-react": "^1.3.2",
|
||||
"apexcharts": "^3.36.3",
|
||||
"apexcharts": "^3.37.2",
|
||||
"axios": "^0.27.2",
|
||||
"change-case": "^4.1.2",
|
||||
"csstype": "^3.1.0",
|
||||
"date-fns": "^2.29.2",
|
||||
"csstype": "^3.1.1",
|
||||
"date-fns": "^2.29.3",
|
||||
"framer-motion": "^6.5.1",
|
||||
"highlight.js": "^11.6.0",
|
||||
"highlight.js": "^11.7.0",
|
||||
"history": "^5.3.0",
|
||||
"jsx-runtime": "^1.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"notistack": "^3.0.0-alpha.7",
|
||||
"notistack": "^3.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"numeral": "^2.0.6",
|
||||
"pusher-js": "^8.0.2",
|
||||
"react": "^17.0.2",
|
||||
"react-apexcharts": "^1.4.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-dropzone": "^14.2.2",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-helmet-async": "^1.3.0",
|
||||
"react-hook-form": "^7.34.2",
|
||||
"react-hook-form": "^7.43.7",
|
||||
"react-intersection-observer": "^8.34.0",
|
||||
"react-lazy-load-image-component": "^1.5.5",
|
||||
"react-number-format": "^5.1.1",
|
||||
"react-lazy-load-image-component": "^1.5.6",
|
||||
"react-number-format": "^5.1.4",
|
||||
"react-quill": "2.0.0-beta.4",
|
||||
"react-router": "^6.3.0",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"simplebar": "^5.3.8",
|
||||
"simplebar-react": "^2.4.1",
|
||||
"stylis": "^4.1.1",
|
||||
"react-router": "^6.9.0",
|
||||
"react-router-dom": "^6.9.0",
|
||||
"simplebar": "^5.3.9",
|
||||
"simplebar-react": "^2.4.3",
|
||||
"stylis": "^4.1.3",
|
||||
"stylis-plugin-rtl": "^2.1.1",
|
||||
"vite": "^3.0.9",
|
||||
"vite-plugin-svgr": "^2.2.1",
|
||||
"vite": "^3.2.5",
|
||||
"vite-plugin-svgr": "^2.4.0",
|
||||
"yup": "^0.32.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.13",
|
||||
"@babel/eslint-parser": "^7.18.9",
|
||||
"@babel/core": "^7.21.3",
|
||||
"@babel/eslint-parser": "^7.21.3",
|
||||
"@babel/plugin-syntax-flow": "^7.18.6",
|
||||
"@babel/plugin-transform-react-jsx": "^7.18.10",
|
||||
"@types/lodash": "^4.14.184",
|
||||
"@babel/plugin-transform-react-jsx": "^7.21.0",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"@types/react": "^17.0.48",
|
||||
"@types/react-dom": "^17.0.17",
|
||||
"@types/react": "^17.0.53",
|
||||
"@types/react-dom": "^17.0.19",
|
||||
"@types/react-lazy-load-image-component": "^1.5.2",
|
||||
"@types/stylis": "^4.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.35.1",
|
||||
"@typescript-eslint/parser": "^5.35.1",
|
||||
"eslint": "^8.22.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.56.0",
|
||||
"@typescript-eslint/parser": "^5.56.0",
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-config-airbnb": "19.0.4",
|
||||
"eslint-config-airbnb-typescript": "^16.2.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-config-react-app": "7.0.0",
|
||||
"eslint-import-resolver-typescript": "^2.7.1",
|
||||
"eslint-plugin-flowtype": "^8.0.3",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jsx-a11y": "6.5.1",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.31.0",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "4.3.0",
|
||||
"prettier": "^2.7.1",
|
||||
"typescript": "^4.8.2",
|
||||
"vite-plugin-pwa": "^0.12.3"
|
||||
"prettier": "^2.8.6",
|
||||
"typescript": "^4.9.5",
|
||||
"vite-plugin-pwa": "^0.12.8"
|
||||
}
|
||||
}
|
||||
|
||||
3369
frontend/client-portal/pnpm-lock.yaml
generated
3369
frontend/client-portal/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
5
frontend/client-portal/src/@types/claim.ts
Normal file
5
frontend/client-portal/src/@types/claim.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export type ClaimStatusType = {
|
||||
name: string;
|
||||
value: number;
|
||||
color: string;
|
||||
};
|
||||
11
frontend/client-portal/src/@types/policy.ts
Normal file
11
frontend/client-portal/src/@types/policy.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export type PolicyProps = {
|
||||
myLimit: {
|
||||
balance: number;
|
||||
total: number;
|
||||
percentage: number;
|
||||
};
|
||||
lockLimit: {
|
||||
balance: number;
|
||||
percentage: number;
|
||||
};
|
||||
};
|
||||
66
frontend/client-portal/src/@types/table.ts
Normal file
66
frontend/client-portal/src/@types/table.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
|
||||
/* ------------------------------- pagination ------------------------------- */
|
||||
export type PaginationTableProps = {
|
||||
current_page: number;
|
||||
from: number;
|
||||
last_page: number;
|
||||
links: [];
|
||||
path: string;
|
||||
per_page: number;
|
||||
to: number;
|
||||
total: number;
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------- order --------------------------------- */
|
||||
export type Order = 'asc' | 'desc';
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* --------------------------------- filter --------------------------------- */
|
||||
export type DivisionDataProps = {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* -------------------------------- headcell -------------------------------- */
|
||||
export type HeadCell<DataType> = {
|
||||
id: Extract<keyof DataType, string>;
|
||||
align: string;
|
||||
label: string;
|
||||
isSort: boolean;
|
||||
width?: number;
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* ----------------------------------- row ---------------------------------- */
|
||||
export type TableListProps<DataType> = {
|
||||
headCells?: HeadCell<DataType>[];
|
||||
rows?: Array<DataType>;
|
||||
paginations: {
|
||||
page: number;
|
||||
setPage: Dispatch<SetStateAction<number>>;
|
||||
rowsPerPage: number;
|
||||
setRowsPerPage: Dispatch<SetStateAction<number>>;
|
||||
paginationTable: PaginationTableProps;
|
||||
setPaginationTable: Dispatch<SetStateAction<PaginationTableProps>>;
|
||||
};
|
||||
orders: {
|
||||
order: Order;
|
||||
setOrder: Dispatch<SetStateAction<Order>>;
|
||||
orderBy: string;
|
||||
setOrderBy: Dispatch<SetStateAction<string>>;
|
||||
};
|
||||
loadings: {
|
||||
isLoading: boolean;
|
||||
setIsLoading: Dispatch<SetStateAction<boolean>>;
|
||||
};
|
||||
params: {
|
||||
searchParams: URLSearchParams;
|
||||
setSearchParams: any;
|
||||
appliedParams: {};
|
||||
setAppliedParams: Dispatch<SetStateAction<{}>>;
|
||||
};
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
289
frontend/client-portal/src/components/Table.tsx
Normal file
289
frontend/client-portal/src/components/Table.tsx
Normal file
@@ -0,0 +1,289 @@
|
||||
/* ---------------------------------- @mui ---------------------------------- */
|
||||
import { styled } from '@mui/material/styles';
|
||||
import {
|
||||
Paper,
|
||||
Table as TableContent,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Button,
|
||||
TableSortLabel,
|
||||
Box,
|
||||
Card,
|
||||
Grid,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
MenuItem,
|
||||
SelectChangeEvent,
|
||||
Stack,
|
||||
Typography,
|
||||
LinearProgress,
|
||||
linearProgressClasses,
|
||||
} from '@mui/material';
|
||||
import { visuallyHidden } from '@mui/utils';
|
||||
/* ---------------------------------- axios --------------------------------- */
|
||||
import axios from '../utils/axios';
|
||||
/* ---------------------------------- react --------------------------------- */
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
/* -------------------------------- component ------------------------------- */
|
||||
import BaseTablePagination from './BaseTablePagination';
|
||||
/* ---------------------------------- theme --------------------------------- */
|
||||
import palette from '../theme/palette';
|
||||
/* ---------------------------------- utils --------------------------------- */
|
||||
import { UserCurrentCorporateContext } from '../contexts/UserCurrentCorporate';
|
||||
import { fSplit } from '../utils/formatNumber';
|
||||
/* ---------------------------------- types --------------------------------- */
|
||||
import { DivisionDataProps, Order, PaginationTableProps, TableListProps } from '../@types/table';
|
||||
|
||||
/* --------------------------------- styled --------------------------------- */
|
||||
const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
|
||||
height: 10,
|
||||
borderRadius: 6,
|
||||
[`&.${linearProgressClasses.colorPrimary}`]: {
|
||||
backgroundColor: '#D1F1F1',
|
||||
},
|
||||
[`& .${linearProgressClasses.bar}`]: {
|
||||
borderRadius: 6,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
}));
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
export default function Table<T>({
|
||||
headCells,
|
||||
rows,
|
||||
paginations,
|
||||
orders,
|
||||
loadings,
|
||||
params,
|
||||
}: TableListProps<T>) {
|
||||
/* ------------------------------- handle sort ------------------------------ */
|
||||
const handleRequestSort = async (event: React.MouseEvent<unknown>, property: string) => {
|
||||
const isAsc = orders?.orderBy === property && orders?.order === 'asc';
|
||||
|
||||
orders?.setOrder(isAsc ? 'desc' : 'asc');
|
||||
orders?.setOrderBy(property);
|
||||
const parameters = Object.fromEntries([
|
||||
...params.searchParams.entries(),
|
||||
['order', isAsc ? 'desc' : 'asc'],
|
||||
['orderBy', property],
|
||||
]);
|
||||
params.setAppliedParams(parameters);
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* -------------------------- enchanced table head -------------------------- */
|
||||
const EnhancedTableHead = () => {
|
||||
const createSortHandler = (property: string) => (event: React.MouseEvent<unknown>) => {
|
||||
handleRequestSort(event, property);
|
||||
};
|
||||
|
||||
return (
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{headCells &&
|
||||
headCells.map((headCell, index) => (
|
||||
<TableCell
|
||||
key={index}
|
||||
sortDirection={orders?.orderBy === headCell.id ? orders.order : false}
|
||||
// @ts-ignore
|
||||
align={headCell.align}
|
||||
sx={{ padding: 2 }}
|
||||
width={headCell.width ? headCell.width : 'auto'}
|
||||
>
|
||||
{headCell.isSort ? (
|
||||
<TableSortLabel
|
||||
active={orders?.orderBy === headCell.id}
|
||||
direction={orders?.orderBy === headCell.id ? orders.order : 'asc'}
|
||||
onClick={createSortHandler(headCell.id)}
|
||||
>
|
||||
{headCell.label}
|
||||
{orders?.orderBy === headCell.id ? (
|
||||
<Box component="span" sx={visuallyHidden}>
|
||||
{orders.order === 'desc' ? 'sorted descending' : 'sorted ascending'}
|
||||
</Box>
|
||||
) : null}
|
||||
</TableSortLabel>
|
||||
) : (
|
||||
headCell.label
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
);
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* ----------------------------- division field ----------------------------- */
|
||||
// const [divisionValue, setDivisionValue] = useState('all');
|
||||
// const [divisionData, setDivisionData] = useState([]);
|
||||
|
||||
// const handleDivisionChange = (event: SelectChangeEvent) => {
|
||||
// setDivisionValue(event.target.value as string);
|
||||
|
||||
// if (event.target.value === 'all') {
|
||||
// searchParams.delete('division');
|
||||
// const params = Object.fromEntries([...searchParams.entries()]);
|
||||
// setAppliedParams(params);
|
||||
// } else {
|
||||
// const params = Object.fromEntries([
|
||||
// ...searchParams.entries(),
|
||||
// ['division', event.target.value as string],
|
||||
// ]);
|
||||
// setAppliedParams(params);
|
||||
// }
|
||||
// };
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* ------------------------------ Search field ------------------------------ */
|
||||
// const [searchText, setSearchText] = useState('');
|
||||
|
||||
// const handleSearchSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
// event.preventDefault();
|
||||
// setIsLoading(true);
|
||||
// if (searchText === '') {
|
||||
// searchParams.delete('search');
|
||||
// const params = Object.fromEntries([...searchParams.entries()]);
|
||||
// setAppliedParams(params);
|
||||
// } else {
|
||||
// const params = Object.fromEntries([...searchParams.entries(), ['search', searchText]]);
|
||||
// setAppliedParams(params);
|
||||
// }
|
||||
// await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
// setIsLoading(false);
|
||||
// };
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* ------------------------ button change pagination ------------------------ */
|
||||
const onPageChangeHandle = async (
|
||||
event: React.MouseEvent<HTMLButtonElement> | null,
|
||||
newPage: number
|
||||
) => {
|
||||
const parameters = Object.fromEntries([
|
||||
...params.searchParams.entries(),
|
||||
['page', newPage + 1],
|
||||
]);
|
||||
paginations.setPage(newPage);
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
params.setAppliedParams(parameters);
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* --------------------------- row page per limit --------------------------- */
|
||||
const onRowsPerPageChangeHandle = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
params.searchParams.delete('page');
|
||||
const parameters = Object.fromEntries([
|
||||
...params.searchParams.entries(),
|
||||
['per_page', parseInt(event.target.value, 10)],
|
||||
]);
|
||||
|
||||
paginations.setPage(0);
|
||||
paginations.setRowsPerPage(parseInt(event.target.value, 10));
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
params.setAppliedParams(parameters);
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Grid container>
|
||||
{/* Field 1 */}
|
||||
{/* <Grid item xs={12} paddingX="24px" paddingY="20px">
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} lg={3} xl={2}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel id="simple-division-select-lable">Division</InputLabel>
|
||||
<Select
|
||||
labelId="simple-division-select-lable"
|
||||
id="division-select-lable"
|
||||
value={divisionValue}
|
||||
label="Division"
|
||||
onChange={handleDivisionChange}
|
||||
>
|
||||
<MenuItem value="all">All</MenuItem>
|
||||
{divisionData.map((row: DivisionDataProps, index) => (
|
||||
<MenuItem key={index} value={row.id}>
|
||||
{row.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={9} xl={10}>
|
||||
<form onSubmit={handleSearchSubmit}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
label="Search"
|
||||
variant="outlined"
|
||||
onChange={(event) => setSearchText(event.target.value)}
|
||||
value={searchText}
|
||||
fullWidth
|
||||
/>
|
||||
</form>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid> */}
|
||||
{/* End Field 1 */}
|
||||
{/* Field 2 */}
|
||||
<Grid item xs={12}>
|
||||
{/* Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<TableContent aria-label="collapsible table" size="small">
|
||||
{/* Table Header */}
|
||||
<EnhancedTableHead />
|
||||
{/* End Table Header */}
|
||||
{/* Table Body */}
|
||||
<TableBody>
|
||||
{loadings.isLoading ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={headCells?.length} align="center">
|
||||
Loading . . .
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : rows && rows.length >= 1 ? (
|
||||
rows.map((row, rowIndex) => (
|
||||
<TableRow key={rowIndex}>
|
||||
{headCells &&
|
||||
//@ts-ignore
|
||||
headCells.map((head, headIndex) => (
|
||||
//@ts-ignore
|
||||
<TableCell align={head.align} key={headIndex}>
|
||||
{row[head.id]}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={6} align="center">
|
||||
No Data Found
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
{/* End Table Body */}
|
||||
</TableContent>
|
||||
</TableContainer>
|
||||
{/* End Table */}
|
||||
|
||||
{/* Pagination */}
|
||||
<BaseTablePagination
|
||||
count={paginations.paginationTable.total}
|
||||
onPageChange={onPageChangeHandle}
|
||||
page={paginations.page}
|
||||
rowsPerPage={paginations.rowsPerPage}
|
||||
onRowsPerPageChange={onRowsPerPageChangeHandle}
|
||||
/>
|
||||
{/* End Pagination */}
|
||||
</Grid>
|
||||
{/* End Field 2 */}
|
||||
</Grid>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -1,43 +1,167 @@
|
||||
// @mui
|
||||
import { Card, Container, Grid, TableBody, TableCell, TableRow } from '@mui/material';
|
||||
// components
|
||||
/* ---------------------------------- react --------------------------------- */
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
/* ----------------------------------- mui ---------------------------------- */
|
||||
import { Container, Grid } from '@mui/material';
|
||||
/* ------------------------------- components ------------------------------- */
|
||||
import Page from '../../components/Page';
|
||||
// utils
|
||||
import TableList from '../../components/Table';
|
||||
/* ---------------------------------- hooks --------------------------------- */
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
// theme
|
||||
import palette from '../../theme/palette';
|
||||
// section
|
||||
/* -------------------------------- sections -------------------------------- */
|
||||
import CardClaimStatus from '../../sections/claim-report/CardClaimStatus';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const listClaimItems = [
|
||||
{ name: 'Requested', value: 15, color: palette.dark.primary.dark },
|
||||
{ name: 'Approval', value: 20, color: palette.dark.warning.dark },
|
||||
{ name: 'Disbrusment', value: 20, color: palette.dark.success.dark },
|
||||
{ name: 'Rejected', value: 20, color: palette.dark.error.dark },
|
||||
];
|
||||
|
||||
const testingData = [
|
||||
{ label: 'Member ID', value: 'member_id' },
|
||||
{ label: 'Name', value: 'name' },
|
||||
{ label: 'Divisi', value: 'division_id' },
|
||||
];
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/* ---------------------------------- 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';
|
||||
|
||||
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<Order>('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<PaginationTableProps>({
|
||||
current_page: 0,
|
||||
from: 0,
|
||||
last_page: 0,
|
||||
links: [],
|
||||
path: '',
|
||||
per_page: 0,
|
||||
to: 0,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const paginations = {
|
||||
page: page,
|
||||
setPage: setPage,
|
||||
rowsPerPage: rowsPerPage,
|
||||
setRowsPerPage: setRowsPerPage,
|
||||
paginationTable: paginationTable,
|
||||
setPaginationTable: setPaginationTable,
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* -------------------------------- headCell -------------------------------- */
|
||||
const headCells: HeadCell<never>[] = [
|
||||
{
|
||||
id: 'memberId',
|
||||
align: 'left',
|
||||
label: 'Member ID',
|
||||
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 parameters =
|
||||
Object.keys(appliedParams).length !== 0
|
||||
? appliedParams
|
||||
: Object.fromEntries([
|
||||
...searchParams.entries(),
|
||||
['order', orders.order],
|
||||
['orderBy', orders.orderBy],
|
||||
]);
|
||||
|
||||
const claim = await axios.get(`${corporateValue}/claim`, {
|
||||
params: { ...parameters, claimMember: true },
|
||||
});
|
||||
|
||||
setSearchParams(parameters);
|
||||
|
||||
setListClaimStatusItems(claim.data.data.allClaimStatus);
|
||||
setListAllMemberByClaimStatus(claim.data.data.allMembersByClaimStatus.data);
|
||||
setPaginationTable(claim.data.data.allMembersByClaimStatus);
|
||||
|
||||
setIsLoading(false);
|
||||
})();
|
||||
}, [appliedParams, searchParams, order, orderBy, setSearchParams, corporateValue]);
|
||||
|
||||
return (
|
||||
<Page title="Claim Reports">
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} lg={12} md={12}>
|
||||
<CardClaimStatus data={listClaimItems} />
|
||||
<CardClaimStatus data={listClaimStatusItems} />
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={12} md={12}>
|
||||
<Card></Card>
|
||||
<TableList
|
||||
headCells={headCells}
|
||||
rows={listAllMemberByClaimStatus}
|
||||
orders={orders}
|
||||
paginations={paginations}
|
||||
loadings={loadings}
|
||||
params={params}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Container>
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
// @mui
|
||||
import { Typography, Container, Grid } from '@mui/material';
|
||||
// hooks
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
// components
|
||||
import Page from '../../components/Page';
|
||||
// theme
|
||||
import CardNotification from '../../sections/dashboard/CardNotification';
|
||||
import CardBalance from '../../sections/dashboard/CardBalance';
|
||||
import TableList from '../../sections/dashboard/TableList';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import axios from '../../utils/axios';
|
||||
import { Stack } from '@mui/system';
|
||||
import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const itemList = [
|
||||
{ info: 'Mohon lengkapi dokumen Alison Born', date: 'Selasa, 13 Februari 23', time: '09:43 WIB' },
|
||||
];
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/* ---------------------------------- types --------------------------------- */
|
||||
|
||||
type PolicyProps = {
|
||||
myLimit: {
|
||||
balance: number;
|
||||
total: number;
|
||||
percentage: number;
|
||||
};
|
||||
lockLimit: {
|
||||
balance: number;
|
||||
percentage: number;
|
||||
};
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* ------------------------------ default data ------------------------------ */
|
||||
const defaultPolicyData = {
|
||||
myLimit: {
|
||||
balance: 0,
|
||||
total: 0,
|
||||
percentage: 0,
|
||||
},
|
||||
lockLimit: {
|
||||
balance: 0,
|
||||
percentage: 0,
|
||||
},
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
export default function Dashboard() {
|
||||
const { themeStretch } = useSettings();
|
||||
const { corporateValue } = useContext(UserCurrentCorporateContext);
|
||||
|
||||
// const [tableData, setTableData] = useState([]);
|
||||
const [policyData, setPolicyData] = useState<PolicyProps>(defaultPolicyData);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
setPolicyData(defaultPolicyData);
|
||||
await new Promise((resolve) => setTimeout(resolve, 250));
|
||||
const dashboard = await axios.get(`${corporateValue}/policy`);
|
||||
setPolicyData(dashboard.data.policy);
|
||||
})();
|
||||
}, [corporateValue]);
|
||||
|
||||
return (
|
||||
<Page title="Dashboard">
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="h3" component="h1" paragraph>
|
||||
Dashboard
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} lg={6} md={12}>
|
||||
<CardNotification data={itemList} />
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={6} md={12}>
|
||||
<CardBalance data={policyData} />
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={12} md={12}>
|
||||
<TableList />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
290
frontend/client-portal/src/pages/Dashboard/Index.tsx
Executable file
290
frontend/client-portal/src/pages/Dashboard/Index.tsx
Executable file
@@ -0,0 +1,290 @@
|
||||
// @mui
|
||||
import { styled } from '@mui/material/styles';
|
||||
import {
|
||||
Typography,
|
||||
Container,
|
||||
Grid,
|
||||
Button,
|
||||
IconButton,
|
||||
LinearProgress,
|
||||
linearProgressClasses,
|
||||
} from '@mui/material';
|
||||
// hooks
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
// components
|
||||
import Page from '../../components/Page';
|
||||
// theme
|
||||
import CardNotification from '../../sections/dashboard/CardNotification';
|
||||
import CardPolicy from '../../sections/dashboard/CardPolicy';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import axios from '../../utils/axios';
|
||||
import { Stack } from '@mui/system';
|
||||
import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate';
|
||||
import { PolicyProps } from '../../@types/policy';
|
||||
import Table from '../../components/Table';
|
||||
import { HeadCell, Order, PaginationTableProps } from '../../@types/table';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import palette from '../../theme/palette';
|
||||
import { MoreVert as MoreVertIcon } from '@mui/icons-material';
|
||||
import TableList from '../../sections/dashboard/TableList';
|
||||
import { fSplit } from '../../utils/formatNumber';
|
||||
|
||||
const itemList = [
|
||||
{ info: 'Mohon lengkapi dokumen Alison Born', date: 'Selasa, 13 Februari 23', time: '09:43 WIB' },
|
||||
{ info: 'Mohon lengkapi dokumen Alison Born', date: 'Selasa, 13 Februari 23', time: '09:43 WIB' },
|
||||
{ info: 'Mohon lengkapi dokumen Alison Born', date: 'Selasa, 13 Februari 23', time: '09:43 WIB' },
|
||||
{ info: 'Mohon lengkapi dokumen Alison Born', date: 'Selasa, 13 Februari 23', time: '09:43 WIB' },
|
||||
];
|
||||
|
||||
/* ------------------------------ default data ------------------------------ */
|
||||
const defaultPolicyData = {
|
||||
myLimit: {
|
||||
balance: 0,
|
||||
total: 0,
|
||||
percentage: 0,
|
||||
},
|
||||
lockLimit: {
|
||||
balance: 0,
|
||||
percentage: 0,
|
||||
},
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
export default function Index() {
|
||||
const { themeStretch } = useSettings();
|
||||
const { corporateValue } = useContext(UserCurrentCorporateContext);
|
||||
|
||||
const [memberData, setMemberData] = useState([]);
|
||||
const [policyData, setPolicyData] = useState<PolicyProps>(defaultPolicyData);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* setting up for the table */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
const loadings = {
|
||||
isLoading: isLoading,
|
||||
setIsLoading: setIsLoading,
|
||||
};
|
||||
|
||||
/* ----------------------------- limit progress ----------------------------- */
|
||||
const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
|
||||
height: 10,
|
||||
borderRadius: 6,
|
||||
[`&.${linearProgressClasses.colorPrimary}`]: {
|
||||
backgroundColor: '#D1F1F1',
|
||||
},
|
||||
[`& .${linearProgressClasses.bar}`]: {
|
||||
borderRadius: 6,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
}));
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* ------------------------------ handle params ----------------------------- */
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [appliedParams, setAppliedParams] = useState({});
|
||||
|
||||
const params = {
|
||||
searchParams: searchParams,
|
||||
setSearchParams: setSearchParams,
|
||||
appliedParams: appliedParams,
|
||||
setAppliedParams: setAppliedParams,
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* ------------------------------ handle order ------------------------------ */
|
||||
const [order, setOrder] = useState<Order>('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<PaginationTableProps>({
|
||||
current_page: 0,
|
||||
from: 0,
|
||||
last_page: 0,
|
||||
links: [],
|
||||
path: '',
|
||||
per_page: 0,
|
||||
to: 0,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const paginations = {
|
||||
page: page,
|
||||
setPage: setPage,
|
||||
rowsPerPage: rowsPerPage,
|
||||
setRowsPerPage: setRowsPerPage,
|
||||
paginationTable: paginationTable,
|
||||
setPaginationTable: setPaginationTable,
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* -------------------------------- headCell -------------------------------- */
|
||||
const headCells: HeadCell<never>[] = [
|
||||
{
|
||||
id: 'memberId',
|
||||
align: 'left',
|
||||
label: 'Member ID',
|
||||
isSort: true,
|
||||
},
|
||||
{
|
||||
id: 'fullName',
|
||||
align: 'center',
|
||||
label: 'Name',
|
||||
isSort: true,
|
||||
},
|
||||
{
|
||||
id: 'division',
|
||||
align: 'center',
|
||||
label: 'Divisi',
|
||||
isSort: true,
|
||||
},
|
||||
{
|
||||
id: 'limit',
|
||||
align: 'center',
|
||||
label: 'Limit',
|
||||
isSort: false,
|
||||
// width: 170,
|
||||
},
|
||||
{
|
||||
id: 'status',
|
||||
align: 'center',
|
||||
label: 'Status',
|
||||
isSort: true,
|
||||
},
|
||||
{
|
||||
id: 'action',
|
||||
align: 'right',
|
||||
label: '',
|
||||
isSort: false,
|
||||
},
|
||||
];
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* ----------------------------- handler action ----------------------------- */
|
||||
const handleAction = () => {
|
||||
alert('action');
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
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]]);
|
||||
|
||||
// get data policy, division, member using axios
|
||||
const corporatePolicyLimit = await axios.get(`${corporateValue}/policy`);
|
||||
const corporateDivision = await axios.get(`${corporateValue}/division`);
|
||||
const corporateMembers = await axios.get(`${corporateValue}/members`, {
|
||||
params: { ...parameters },
|
||||
});
|
||||
|
||||
setPolicyData(corporatePolicyLimit.data.data);
|
||||
|
||||
setSearchParams(parameters);
|
||||
setMemberData(corporateMembers.data.data);
|
||||
setPaginationTable(corporateMembers.data);
|
||||
setRowsPerPage(corporateMembers.data.per_page);
|
||||
|
||||
setIsLoading(false);
|
||||
})();
|
||||
}, [appliedParams, searchParams, order, orderBy, setSearchParams, corporateValue]);
|
||||
|
||||
const newMemberData: any = memberData.map((obj: any) => {
|
||||
return {
|
||||
...obj,
|
||||
limit: (
|
||||
<Stack>
|
||||
<BorderLinearProgress variant="determinate" value={obj.limit.percentage} sx={{ mb: 1 }} />
|
||||
<Typography sx={{ typography: 'caption', color: '#637381' }}>
|
||||
{fSplit(obj.limit.current)} / {fSplit(obj.limit.total)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
),
|
||||
status:
|
||||
obj.status === 1 ? (
|
||||
<Button
|
||||
sx={{
|
||||
backgroundColor: 'rgba(84, 214, 44, 0.16)',
|
||||
color: palette.dark.success.dark,
|
||||
paddingY: 0,
|
||||
'&:hover': {
|
||||
backgroundColor: 'rgba(84, 214, 44, 0.32)',
|
||||
color: palette.dark.success.darker,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Active
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
sx={{
|
||||
backgroundColor: 'rgba(255, 72, 66, 0.16)',
|
||||
color: palette.dark.error.dark,
|
||||
paddingY: 0,
|
||||
'&:hover': {
|
||||
backgroundColor: 'rgba(255, 72, 66, 0.32)',
|
||||
color: palette.dark.error.darker,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Inactive
|
||||
</Button>
|
||||
),
|
||||
action: (
|
||||
<IconButton onClick={handleAction}>
|
||||
<MoreVertIcon />
|
||||
</IconButton>
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Page title="Dashboard">
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="h3" component="h1" paragraph>
|
||||
Dashboard
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} lg={6} md={12}>
|
||||
<CardNotification data={itemList} />
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={6} md={12}>
|
||||
<CardPolicy data={policyData} />
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={12} md={12}>
|
||||
<Table
|
||||
headCells={headCells}
|
||||
rows={newMemberData}
|
||||
orders={orders}
|
||||
paginations={paginations}
|
||||
loadings={loadings}
|
||||
params={params}
|
||||
/>
|
||||
{/* <TableList /> */}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -144,7 +144,7 @@ export default function Router() {
|
||||
const Login = Loadable(lazy(() => import('../pages/auth/Login')));
|
||||
|
||||
// Dashboard
|
||||
const Dashboard = Loadable(lazy(() => import('../pages/Dashboard/Dashboard')));
|
||||
const Dashboard = Loadable(lazy(() => import('../pages/Dashboard/Index')));
|
||||
const NotFound = Loadable(lazy(() => import('../pages/Page404')));
|
||||
|
||||
// Alarm Center
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
// @mui
|
||||
import { styled } from '@mui/material/styles';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Typography,
|
||||
Stack,
|
||||
LinearProgress,
|
||||
linearProgressClasses,
|
||||
} from '@mui/material';
|
||||
// utils
|
||||
import { fCurrency } from '../../utils/formatNumber';
|
||||
// components
|
||||
import Iconify from '../../components/Iconify';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const RootStyle = styled(Card)(({ theme }) => ({
|
||||
boxShadow: 'none',
|
||||
padding: theme.spacing(3),
|
||||
color: 'black',
|
||||
backgroundColor: theme.palette.grey[200],
|
||||
maxHeight: '240px',
|
||||
}));
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const INITIAL = '500.000.000';
|
||||
const TOTAL = 375000000;
|
||||
const PERCENT = 75;
|
||||
|
||||
export default function BalanceCard(props: any) {
|
||||
const { setOpenPopup } = props;
|
||||
|
||||
const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
|
||||
height: 10,
|
||||
borderRadius: 6,
|
||||
[`&.${linearProgressClasses.colorPrimary}`]: {
|
||||
backgroundColor: theme.palette.grey[theme.palette.mode === 'light' ? 300 : 800],
|
||||
},
|
||||
[`& .${linearProgressClasses.bar}`]: {
|
||||
borderRadius: 6,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
}));
|
||||
|
||||
return (
|
||||
<RootStyle>
|
||||
<Stack direction="row" justifyContent="space-between" sx={{ mb: 1 }}>
|
||||
<div>
|
||||
<Typography variant="body2" component="span" sx={{ opacity: 0.72 }}>
|
||||
Total Limit
|
||||
</Typography>
|
||||
<Typography sx={{ typography: 'body2' }}>{fCurrency(TOTAL)}</Typography>
|
||||
<Typography sx={{ typography: 'caption', color: '#919EAB' }}>/ {INITIAL}</Typography>
|
||||
</div>
|
||||
|
||||
<Stack direction="row" alignItems="center" justifyContent="center">
|
||||
<Typography variant="h5" sx={{ ml: 0.5 }}>
|
||||
{PERCENT}%
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<BorderLinearProgress variant="determinate" value={PERCENT} sx={{ mb: 1 }} />
|
||||
|
||||
<Stack sx={{ backgroundColor: '#B2E8E8', paddingY: 1, paddingX: 1.5, mb: 2 }}>
|
||||
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:lock-alt"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Lock Fund ( 25% )
|
||||
</Typography>
|
||||
</Typography>
|
||||
<Typography sx={{ typography: 'caption', color: '#637381' }}>
|
||||
125.000.000 / 125.000.000
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<Iconify icon="bi:clipboard-check-fill" />}
|
||||
fullWidth={true}
|
||||
onClick={() => setOpenPopup(true)}
|
||||
>
|
||||
Submit Claim
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<Iconify icon="heroicons-solid:cash" />}
|
||||
fullWidth={true}
|
||||
>
|
||||
Top Up
|
||||
</Button>
|
||||
</Stack>
|
||||
</RootStyle>
|
||||
);
|
||||
}
|
||||
@@ -26,9 +26,10 @@ type NotificationProps = {
|
||||
|
||||
const RootNotificationStyle = styled(Card)(({ theme }) => ({
|
||||
boxShadow: 'none',
|
||||
padding: '1rem 0.5rem',
|
||||
padding: '1.5rem',
|
||||
color: 'black',
|
||||
backgroundColor: theme.palette.grey[200],
|
||||
height: '100%',
|
||||
maxHeight: '240px',
|
||||
}));
|
||||
|
||||
@@ -37,6 +38,10 @@ const ItemNotificationStyle = styled(Card)(({ theme }) => ({
|
||||
padding: theme.spacing(1),
|
||||
borderRadius: 0.5,
|
||||
color: 'black',
|
||||
marginTop: 2,
|
||||
overflowY: 'auto',
|
||||
maxHeight: '154px',
|
||||
gap: '0.5rem',
|
||||
}));
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
@@ -95,11 +100,11 @@ export default function CardNotification({ data }: NotificationProps) {
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
<ItemNotificationStyle sx={{ marginTop: 2, overflowY: 'auto', maxHeight: '154px' }}>
|
||||
<ItemNotificationStyle>
|
||||
{data
|
||||
? data.map(({ info, date, time }, key) => (
|
||||
<div key={key}>
|
||||
{key >= 1 ? <Divider sx={{ marginY: 0.5 }} /> : ''}
|
||||
? data.map(({ info, date, time }, index) => (
|
||||
<div key={index}>
|
||||
{index >= 1 ? <Divider sx={{ marginY: 0.5 }} /> : ''}
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="center">
|
||||
<Stack direction="column" justifyContent="flex-start" alignItems="flex-start">
|
||||
<Typography sx={{ typography: 'caption' }}>{info}</Typography>
|
||||
|
||||
@@ -20,7 +20,7 @@ import DialogClaimSubmitMember from './DialogClaimSubmitMember';
|
||||
|
||||
/* ---------------------------------- types --------------------------------- */
|
||||
|
||||
type CardBalanceProps = {
|
||||
type CardPolicyProps = {
|
||||
data: {
|
||||
myLimit: {
|
||||
balance: number;
|
||||
@@ -60,7 +60,7 @@ const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
export default function CardBalance(props: CardBalanceProps) {
|
||||
export default function CardPolicy(props: CardPolicyProps) {
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const [dialogTitle, setDialogTitle] = useState('');
|
||||
const [isDialog, setIsDialog] = useState('');
|
||||
@@ -1,315 +0,0 @@
|
||||
// @mui
|
||||
import {
|
||||
Autocomplete,
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
Collapse,
|
||||
IconButton,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
OutlinedInput,
|
||||
Paper,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
Badge,
|
||||
Tab,
|
||||
Tabs,
|
||||
CardHeader,
|
||||
Stack,
|
||||
Menu,
|
||||
ButtonGroup,
|
||||
Pagination,
|
||||
TablePagination,
|
||||
Grid,
|
||||
} from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../utils/axios';
|
||||
import { LaravelPaginatedData } from '../../@types/paginated-data';
|
||||
import { Member } from '../../@types/member';
|
||||
import Iconify from '../../components/Iconify';
|
||||
|
||||
export default function DashboardTable() {
|
||||
const navigate = useNavigate();
|
||||
const { themeStretch } = useSettings();
|
||||
const { corporate_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? '';
|
||||
setSearchText(newSearchText);
|
||||
};
|
||||
|
||||
const handleSearchSubmit = (event: any) => {
|
||||
event.preventDefault();
|
||||
props.onSearch(searchText); // Trigger to Parent
|
||||
};
|
||||
|
||||
// useEffect(() => {
|
||||
// // Trigger First Search
|
||||
// setSearchText(searchParams.get('search') ?? '');
|
||||
// }, [searchParams]);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ flex: '1' }}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
ref={searchInput}
|
||||
label="Search"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
onChange={handleSearchChange}
|
||||
value={searchText}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
function ImportForm(props: any) {
|
||||
// IMPORT
|
||||
// Create Button Menu
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const createMenu = Boolean(anchorEl);
|
||||
const importForm = useRef<HTMLInputElement>(null);
|
||||
const [currentImportFileName, setCurrentImportFileName] = useState(null);
|
||||
|
||||
const handleImportChange = (event: any) => {
|
||||
if (event.target.files[0]) {
|
||||
setCurrentImportFileName(event.target.files[0].name);
|
||||
} else {
|
||||
setCurrentImportFileName(null);
|
||||
}
|
||||
};
|
||||
|
||||
const options = ['All', 'Option 2'];
|
||||
const [value, setValue] = React.useState<string | null>(options[0]);
|
||||
const [inputValue, setInputValue] = React.useState('');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Stack direction={'row'} justifyContent="space-between" spacing={2} sx={{ p: 2 }}>
|
||||
{/* Filter Division */}
|
||||
<Autocomplete
|
||||
value={value}
|
||||
onChange={(event: any, newValue: string | null) => {
|
||||
setValue(newValue);
|
||||
}}
|
||||
inputValue={inputValue}
|
||||
onInputChange={(event, newInputValue) => {
|
||||
setInputValue(newInputValue);
|
||||
}}
|
||||
id="controllable-states-demo"
|
||||
options={options}
|
||||
sx={{ minWidth: 240 }}
|
||||
renderInput={(params) => <TextField {...params} label="Division" />}
|
||||
/>
|
||||
{/* Search */}
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
|
||||
{/* Button Import */}
|
||||
<Button
|
||||
id="import-button"
|
||||
variant="outlined"
|
||||
startIcon={<Iconify icon="eva:download-fill" />}
|
||||
sx={{ p: 1.8, minWidth: '104px' }}
|
||||
// onClick={() => {}}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
{/* <input
|
||||
type="file"
|
||||
id="file"
|
||||
ref={importForm}
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleImportChange}
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain"
|
||||
/> */}
|
||||
{/* Button Add Task */}
|
||||
<Button variant="contained" startIcon={<AddIcon />} sx={{ p: 1.8, minWidth: '142px' }}>
|
||||
Add Data
|
||||
</Button>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData(member: Member): Member {
|
||||
return {
|
||||
...member,
|
||||
};
|
||||
}
|
||||
|
||||
// Generate the every row of the table
|
||||
// function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
// const { row } = props;
|
||||
// const [open, setOpen] = React.useState(true);
|
||||
|
||||
// return (
|
||||
// <React.Fragment>
|
||||
// <TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
// <TableCell>
|
||||
// <IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
// {open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
// </IconButton>
|
||||
// </TableCell>
|
||||
// <TableCell align="left">{row.member_id}</TableCell>
|
||||
// <TableCell align="left">{row.payor_id}</TableCell>
|
||||
// <TableCell align="left">{row.name}</TableCell>
|
||||
// <TableCell align="left">{row.nik}</TableCell>
|
||||
// <TableCell align="left">{row.nric}</TableCell>
|
||||
|
||||
// <TableCell align="right">
|
||||
// <Button variant="outlined" color="success" size="small">
|
||||
// Active
|
||||
// </Button>
|
||||
// </TableCell>
|
||||
// {/* <TableCell align="right"><Button variant="outlined" color="error" size="small">Disable</Button></TableCell> */}
|
||||
// </TableRow>
|
||||
// {/* COLLAPSIBLE ROW */}
|
||||
// <TableRow>
|
||||
// <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
|
||||
// <Collapse in={open} timeout="auto" unmountOnExit>
|
||||
// <Box sx={{ borderBottom: 1 }}>
|
||||
// <Typography variant="body2" gutterBottom component="div">
|
||||
// <Grid></Grid>
|
||||
// </Typography>
|
||||
// </Box>
|
||||
// </Collapse>
|
||||
// </TableCell>
|
||||
// </TableRow>
|
||||
// </React.Fragment>
|
||||
// );
|
||||
// }
|
||||
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>({
|
||||
current_page: 1,
|
||||
data: [],
|
||||
path: '',
|
||||
first_page_url: '',
|
||||
last_page: 1,
|
||||
last_page_url: '',
|
||||
next_page_url: '',
|
||||
prev_page_url: '',
|
||||
per_page: 10,
|
||||
from: 0,
|
||||
to: 0,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const loadDataTableData = async (appliedFilter: any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/members', { params: filter });
|
||||
|
||||
setDataTableData(response.data.members);
|
||||
setDataTableLoading(false);
|
||||
};
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const applyFilter = async (searchFilter: string) => {
|
||||
await loadDataTableData({ search: searchFilter });
|
||||
setSearchParams({ search: searchFilter });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<ImportForm />
|
||||
<Stack>
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
MemberID
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Name
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Divisi
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Limit
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="right" width={100}>
|
||||
Status
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="right" width={100}>
|
||||
Action
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">
|
||||
No Data Found
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : dataTableData.data.length === 0 ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">
|
||||
No Data
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{/* {dataTableData.data.map((row) => (
|
||||
<Row key={row.id} row={row} />
|
||||
))} */}
|
||||
Testing
|
||||
</TableBody>
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
{/* <TablePagination
|
||||
rowsPerPageOptions={[5, 10, 25]}
|
||||
component="div"
|
||||
count={rows.length}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
onPageChange={handleChangePage}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
/> */}
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
// @mui
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { Button, Card, Divider, Link, Typography, Stack } from '@mui/material';
|
||||
import { ChevronRight } from '@mui/icons-material';
|
||||
// components
|
||||
import Iconify from '../../components/Iconify';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const RootStyle = styled(Card)(({ theme }) => ({
|
||||
boxShadow: 'none',
|
||||
padding: '1rem 0.5rem',
|
||||
color: 'black',
|
||||
backgroundColor: theme.palette.grey[200],
|
||||
maxHeight: '240px',
|
||||
}));
|
||||
|
||||
const ItemStyle = styled(Card)(({ theme }) => ({
|
||||
boxShadow: 'none',
|
||||
padding: theme.spacing(1),
|
||||
borderRadius: 0.5,
|
||||
color: 'black',
|
||||
maxHeight: '170px',
|
||||
}));
|
||||
|
||||
const itemList = [
|
||||
{ info: 'Mohon lengkapi dokumen Alison Born', date: 'Selasa, 13 Februari 23', time: '09:43 WIB' },
|
||||
];
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function NotificationCard() {
|
||||
return (
|
||||
<RootStyle>
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="center">
|
||||
<Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
component="span"
|
||||
sx={{ display: 'flex', alignItems: 'center' }}
|
||||
>
|
||||
<Iconify icon="eva:bell-fill" marginRight={0.75} />
|
||||
Notification
|
||||
<div
|
||||
style={{
|
||||
width: '12px',
|
||||
height: '12px',
|
||||
backgroundColor: '#19BBBB',
|
||||
marginLeft: '0.5rem',
|
||||
borderRadius: '50%',
|
||||
}}
|
||||
/>
|
||||
</Typography>
|
||||
</Typography>
|
||||
<Button sx={{ typography: 'body2' }} endIcon={<ChevronRight />}>
|
||||
View All
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
<Stack sx={{ marginTop: 2 }}>
|
||||
<ItemStyle>
|
||||
{itemList.map(({ info, date, time }, key) => (
|
||||
<div key={key}>
|
||||
{key >= 1 ? <Divider sx={{ marginY: 0.5 }} /> : ''}
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="center">
|
||||
<Stack direction="column" justifyContent="flex-start" alignItems="flex-start">
|
||||
<Typography sx={{ typography: 'caption' }}>{info}</Typography>
|
||||
<Link
|
||||
component="button"
|
||||
variant="caption"
|
||||
underline="always"
|
||||
onClick={() => {
|
||||
alert('Info Detail');
|
||||
}}
|
||||
>
|
||||
Info Detail
|
||||
</Link>
|
||||
</Stack>
|
||||
<Stack direction="column" justifyContent="flex-start" alignItems="flex-start">
|
||||
<Typography sx={{ typography: 'caption', color: '#656565' }}>{date}</Typography>
|
||||
<Typography sx={{ typography: 'caption', color: '#656565' }}>{time}</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</div>
|
||||
))}
|
||||
</ItemStyle>
|
||||
</Stack>
|
||||
|
||||
{/* <BorderLinearProgress variant="determinate" value={50} sx={{ mb: 1 }} />
|
||||
|
||||
<Stack sx={{ backgroundColor: '#B2E8E8', paddingY: 1, paddingX: 1.5, mb: 2 }}>
|
||||
<Typography sx={{ typography: 'caption' }}>Lock Fund ( 25% )</Typography>
|
||||
<Typography sx={{ typography: 'caption' }}>125.000.000 / 125.000.000</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Button variant="outlined" fullWidth={true}>
|
||||
Submit Claim
|
||||
</Button>
|
||||
<Button variant="contained" startIcon={<Payments />} fullWidth={true}>
|
||||
Top Up
|
||||
</Button>
|
||||
</Stack> */}
|
||||
</RootStyle>
|
||||
);
|
||||
}
|
||||
@@ -1,443 +0,0 @@
|
||||
/* ---------------------------------- @mui ---------------------------------- */
|
||||
import { styled } from '@mui/material/styles';
|
||||
import {
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Button,
|
||||
TableSortLabel,
|
||||
Box,
|
||||
IconButton,
|
||||
Card,
|
||||
Grid,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
MenuItem,
|
||||
SelectChangeEvent,
|
||||
Stack,
|
||||
Typography,
|
||||
LinearProgress,
|
||||
linearProgressClasses,
|
||||
} from '@mui/material';
|
||||
import { visuallyHidden } from '@mui/utils';
|
||||
/* ---------------------------------- axios --------------------------------- */
|
||||
import axios from '../../utils/axios';
|
||||
/* ---------------------------------- react --------------------------------- */
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
/* -------------------------------- component ------------------------------- */
|
||||
import Iconify from '../../components/Iconify';
|
||||
import BaseTablePagination from '../../components/BaseTablePagination';
|
||||
/* ---------------------------------- theme --------------------------------- */
|
||||
import palette from '../../theme/palette';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate';
|
||||
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;
|
||||
division: string;
|
||||
limit: {
|
||||
current: number;
|
||||
total: number;
|
||||
percentage: number;
|
||||
};
|
||||
status: number;
|
||||
};
|
||||
|
||||
type Order = 'asc' | 'desc';
|
||||
|
||||
interface HeadCell {
|
||||
id: string;
|
||||
align: string;
|
||||
label: string;
|
||||
isSort: boolean;
|
||||
}
|
||||
|
||||
interface EnhancedTableProps {
|
||||
onRequestSort: (event: React.MouseEvent<unknown>, property: string) => void;
|
||||
order: Order;
|
||||
orderBy: string;
|
||||
}
|
||||
|
||||
type DivisionDataProps = {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* --------------------------------- styled --------------------------------- */
|
||||
const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
|
||||
height: 10,
|
||||
borderRadius: 6,
|
||||
[`&.${linearProgressClasses.colorPrimary}`]: {
|
||||
backgroundColor: '#D1F1F1',
|
||||
},
|
||||
[`& .${linearProgressClasses.bar}`]: {
|
||||
borderRadius: 6,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
}));
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* -------------------------- enchanced table head -------------------------- */
|
||||
const headCells: readonly HeadCell[] = [
|
||||
{
|
||||
id: 'member_id',
|
||||
align: 'left',
|
||||
label: 'Member ID',
|
||||
isSort: true,
|
||||
},
|
||||
{
|
||||
id: 'name',
|
||||
align: 'center',
|
||||
label: 'Name',
|
||||
isSort: true,
|
||||
},
|
||||
{
|
||||
id: 'division',
|
||||
align: 'center',
|
||||
label: 'Divisi',
|
||||
isSort: false,
|
||||
},
|
||||
{
|
||||
id: 'limit',
|
||||
align: 'center',
|
||||
label: 'Limit',
|
||||
isSort: false,
|
||||
},
|
||||
{
|
||||
id: 'active',
|
||||
align: 'center',
|
||||
label: 'Status',
|
||||
isSort: true,
|
||||
},
|
||||
];
|
||||
|
||||
function EnhancedTableHead({ order, orderBy, onRequestSort }: EnhancedTableProps) {
|
||||
const createSortHandler = (property: string) => (event: React.MouseEvent<unknown>) => {
|
||||
onRequestSort(event, property);
|
||||
};
|
||||
|
||||
return (
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{headCells.map((headCell) => (
|
||||
<TableCell
|
||||
key={headCell.id}
|
||||
sortDirection={orderBy === headCell.id ? order : false}
|
||||
// @ts-ignore
|
||||
align={headCell.align}
|
||||
sx={{ padding: 2 }}
|
||||
>
|
||||
{headCell.isSort ? (
|
||||
<TableSortLabel
|
||||
active={orderBy === headCell.id}
|
||||
direction={orderBy === headCell.id ? order : 'asc'}
|
||||
onClick={createSortHandler(headCell.id)}
|
||||
>
|
||||
{headCell.label}
|
||||
{orderBy === headCell.id ? (
|
||||
<Box component="span" sx={visuallyHidden}>
|
||||
{order === 'desc' ? 'sorted descending' : 'sorted ascending'}
|
||||
</Box>
|
||||
) : null}
|
||||
</TableSortLabel>
|
||||
) : (
|
||||
headCell.label
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
<TableCell align="center">{''}</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
);
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
export default function TableList(props: any) {
|
||||
const { corporateValue } = useContext(UserCurrentCorporateContext);
|
||||
|
||||
const [dataTable, setDataTable] = useState([]);
|
||||
const [paginationTable, setPaginationTable] = useState<PaginationTableProps>({
|
||||
current_page: 0,
|
||||
from: 0,
|
||||
last_page: 0,
|
||||
links: [],
|
||||
path: '',
|
||||
per_page: 0,
|
||||
to: 0,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [appliedParams, setAppliedParams] = useState({});
|
||||
|
||||
const [order, setOrder] = useState<Order>('asc');
|
||||
const [orderBy, setOrderBy] = useState('name');
|
||||
const [page, setPage] = useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = useState(10);
|
||||
|
||||
/* ------------------------------- handle sort ------------------------------ */
|
||||
const handleRequestSort = async (event: React.MouseEvent<unknown>, property: string) => {
|
||||
const isAsc = orderBy === property && order === 'asc';
|
||||
setOrder(isAsc ? 'desc' : 'asc');
|
||||
setOrderBy(property);
|
||||
const params = Object.fromEntries([
|
||||
...searchParams.entries(),
|
||||
['order', isAsc ? 'desc' : 'asc'],
|
||||
['orderBy', property],
|
||||
]);
|
||||
setAppliedParams(params);
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* ----------------------------- division field ----------------------------- */
|
||||
const [divisionValue, setDivisionValue] = useState('all');
|
||||
const [divisionData, setDivisionData] = useState([]);
|
||||
|
||||
const handleDivisionChange = (event: SelectChangeEvent) => {
|
||||
setDivisionValue(event.target.value as string);
|
||||
|
||||
if (event.target.value === 'all') {
|
||||
searchParams.delete('division');
|
||||
const params = Object.fromEntries([...searchParams.entries()]);
|
||||
setAppliedParams(params);
|
||||
} else {
|
||||
const params = Object.fromEntries([
|
||||
...searchParams.entries(),
|
||||
['division', event.target.value as string],
|
||||
]);
|
||||
setAppliedParams(params);
|
||||
}
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* ------------------------------ Search field ------------------------------ */
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
const handleSearchSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
setIsLoading(true);
|
||||
if (searchText === '') {
|
||||
searchParams.delete('search');
|
||||
const params = Object.fromEntries([...searchParams.entries()]);
|
||||
setAppliedParams(params);
|
||||
} else {
|
||||
const params = Object.fromEntries([...searchParams.entries(), ['search', searchText]]);
|
||||
setAppliedParams(params);
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
setIsLoading(false);
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* ------------------------ button change pagination ------------------------ */
|
||||
const onPageChangeHandle = async (
|
||||
event: React.MouseEvent<HTMLButtonElement> | null,
|
||||
newPage: number
|
||||
) => {
|
||||
setIsLoading(true);
|
||||
const params = Object.fromEntries([...searchParams.entries(), ['page', newPage + 1]]);
|
||||
setPage(newPage);
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
setAppliedParams(params);
|
||||
setIsLoading(false);
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* --------------------------- row page per limit --------------------------- */
|
||||
const onRowsPerPageChangeHandle = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setIsLoading(true);
|
||||
searchParams.delete('page');
|
||||
const params = Object.fromEntries([
|
||||
...searchParams.entries(),
|
||||
['per_page', parseInt(event.target.value, 10)],
|
||||
]);
|
||||
setRowsPerPage(parseInt(event.target.value, 10));
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
setAppliedParams(params);
|
||||
setIsLoading(false);
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
setIsLoading(true);
|
||||
|
||||
const division = await axios.get(`${corporateValue}/division`);
|
||||
setDivisionData(division.data);
|
||||
|
||||
const params =
|
||||
Object.keys(appliedParams).length !== 0
|
||||
? appliedParams
|
||||
: Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]);
|
||||
|
||||
const corporateMembers = await axios.get(`${corporateValue}/members`, {
|
||||
params: { ...params, claimMember: false },
|
||||
});
|
||||
|
||||
setSearchParams(params);
|
||||
setDataTable(corporateMembers.data.data);
|
||||
setPaginationTable(corporateMembers.data);
|
||||
setRowsPerPage(corporateMembers.data.per_page);
|
||||
setIsLoading(false);
|
||||
})();
|
||||
}, [appliedParams, searchParams, order, orderBy, setSearchParams, corporateValue]);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Grid container>
|
||||
{/* Field 1 */}
|
||||
<Grid item xs={12} paddingX="24px" paddingY="20px">
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} lg={3} xl={2}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel id="simple-division-select-lable">Division</InputLabel>
|
||||
<Select
|
||||
labelId="simple-division-select-lable"
|
||||
id="division-select-lable"
|
||||
value={divisionValue}
|
||||
label="Division"
|
||||
onChange={handleDivisionChange}
|
||||
>
|
||||
<MenuItem value="all">All</MenuItem>
|
||||
{divisionData.map((row: DivisionDataProps, index) => (
|
||||
<MenuItem key={index} value={row.id}>
|
||||
{row.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={9} xl={10}>
|
||||
<form onSubmit={handleSearchSubmit}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
label="Search"
|
||||
variant="outlined"
|
||||
onChange={(event) => setSearchText(event.target.value)}
|
||||
value={searchText}
|
||||
fullWidth
|
||||
/>
|
||||
</form>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
{/* End Field 1 */}
|
||||
{/* Field 2 */}
|
||||
<Grid item xs={12}>
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table" size="small">
|
||||
<EnhancedTableHead
|
||||
order={order}
|
||||
orderBy={orderBy}
|
||||
onRequestSort={handleRequestSort}
|
||||
/>
|
||||
<TableBody>
|
||||
{isLoading ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={6} align="center">
|
||||
Loading . . .
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : dataTable.length >= 1 ? (
|
||||
dataTable.map((row: DataTableProps, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell align="left">{row.memberId}</TableCell>
|
||||
<TableCell align="center">{row.fullName}</TableCell>
|
||||
<TableCell align="center">{row.division}</TableCell>
|
||||
<TableCell align="center" width={170}>
|
||||
<Stack>
|
||||
<BorderLinearProgress
|
||||
variant="determinate"
|
||||
value={row.limit.percentage}
|
||||
sx={{ mb: 1 }}
|
||||
/>
|
||||
<Typography sx={{ typography: 'caption', color: '#637381' }}>
|
||||
{fSplit(row.limit.current)} / {fSplit(row.limit.total)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
{row.status === 1 ? (
|
||||
<Button
|
||||
sx={{
|
||||
backgroundColor: 'rgba(84, 214, 44, 0.16)',
|
||||
color: palette.dark.success.dark,
|
||||
paddingY: 0,
|
||||
'&:hover': {
|
||||
backgroundColor: 'rgba(84, 214, 44, 0.32)',
|
||||
color: palette.dark.success.darker,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Active
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
sx={{
|
||||
backgroundColor: 'rgba(255, 72, 66, 0.16)',
|
||||
color: palette.dark.error.dark,
|
||||
paddingY: 0,
|
||||
'&:hover': {
|
||||
backgroundColor: 'rgba(255, 72, 66, 0.32)',
|
||||
color: palette.dark.error.darker,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Inactive
|
||||
</Button>
|
||||
)}
|
||||
</TableCell>
|
||||
{/* <TableCell align="right">
|
||||
<IconButton>
|
||||
<Iconify icon="ic:baseline-more-vert" />
|
||||
</IconButton>
|
||||
</TableCell> */}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={6} align="center">
|
||||
No Data Found
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
{/* Pagination */}
|
||||
<BaseTablePagination
|
||||
count={paginationTable.total}
|
||||
onPageChange={onPageChangeHandle}
|
||||
page={page}
|
||||
rowsPerPage={rowsPerPage}
|
||||
onRowsPerPageChange={onRowsPerPageChangeHandle}
|
||||
/>
|
||||
</Grid>
|
||||
{/* End Field 2 */}
|
||||
</Grid>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user