From c886cfa801a661c2c9f6320e307d345663d0ac2d Mon Sep 17 00:00:00 2001 From: pajri Date: Mon, 10 Jun 2024 10:37:41 +0700 Subject: [PATCH 01/13] Url Out sanctum --- Modules/Internal/Routes/api.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Modules/Internal/Routes/api.php b/Modules/Internal/Routes/api.php index 1c5d310f..d25301ec 100644 --- a/Modules/Internal/Routes/api.php +++ b/Modules/Internal/Routes/api.php @@ -72,6 +72,10 @@ Route::prefix('internal')->group(function () { Route::get('linksehat/payments', [PaymentController::class, 'index']); Route::get('linksehat/payments/generate-excel', [PaymentController::class, 'generateExcel']); + Route::get('diagnosis', [RequestLogController::class, 'diagnosis']); + Route::get('drugs', [DrugController::class, 'drugList']); + Route::get('units', [DrugController::class, 'unitList']); + Route::middleware('auth:sanctum')->group(function () { @@ -290,10 +294,10 @@ Route::prefix('internal')->group(function () { Route::post('customer-service/request/final-log', [RequestLogController::class, 'updateFinalLog']); // search diagnosis - Route::get('diagnosis', [RequestLogController::class, 'diagnosis']); + // Route::get('diagnosis', [RequestLogController::class, 'diagnosis']); Route::get('hospitals', [RequestLogController::class, 'hospitals']); - Route::get('drugs', [DrugController::class, 'drugList']); - Route::get('units', [DrugController::class, 'unitList']); + // Route::get('drugs', [DrugController::class, 'drugList']); + // Route::get('units', [DrugController::class, 'unitList']); // insert benefit Route::post('customer-service/request/insert-benefit', [RequestLogBenefitController::class, 'store']); From 605fc72e89e411e1cf17577bd72ae7fef17e977d Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Tue, 18 Jun 2024 08:51:33 +0700 Subject: [PATCH 02/13] Dashboard Client - Portal --- .../Api/CorporateMemberController.php | 22 ++ Modules/Client/Routes/api.php | 5 + database/seeders/NavigationSeeder.php | 101 +++-- database/seeders/PermissionTableSeeder.php | 135 ++++--- .../components/nav-section/vertical/index.tsx | 22 +- .../dashboard/navbar/NavbarVertical.tsx | 50 ++- .../src/pages/Dashboard/Index.tsx | 346 +++++------------- .../src/pages/Dashboard/Index_.tsx | 279 ++++++++++++++ .../src/sections/dashboard/SomethingUsage.tsx | 80 ++++ 9 files changed, 695 insertions(+), 345 deletions(-) create mode 100644 frontend/client-portal/src/pages/Dashboard/Index_.tsx create mode 100644 frontend/client-portal/src/sections/dashboard/SomethingUsage.tsx diff --git a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php index ceb75d10..dd0832f7 100644 --- a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php +++ b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php @@ -21,6 +21,7 @@ use Modules\Client\Transformers\Dashboard\MemberEmployeeDataResources as Dashboa use Box\Spout\Writer\Common\Creator\WriterEntityFactory; use Modules\Client\Transformers\EmployeeData\UserProfile\DataMemberResource as EmployeeDataProfileMemberResource; use Modules\Internal\Services\MemberEnrollmentService; +use Illuminate\Support\Facades\DB; class CorporateMemberController extends Controller { @@ -255,4 +256,25 @@ class CorporateMemberController extends Controller return Helper::responseJson(DataServiceMonitoring::make($data)); } + + public function getDeposit($corporate_id) + { + $deposit = DB::table('corporate_policies') + ->select('total_premi') + ->where('corporate_id','=', $corporate_id) + ->first(); + $usage = DB::table('corporate_employees') + ->join('request_logs', 'request_logs.member_id', '=', 'corporate_employees.member_id') + ->join('request_log_benefits', 'request_log_benefits.request_log_id', '=', 'request_logs.id') + ->where('corporate_employees.corporate_id', '=', $corporate_id) + ->sum('request_log_benefits.amount_approved'); + // Ganti dengan logika Anda untuk mendapatkan data deposit + $deposit = [ + 'deposit' => $deposit->total_premi, + 'limit' => $deposit->total_premi - $usage, + 'usage' => $usage + ]; + + return response()->json($deposit); + } } diff --git a/Modules/Client/Routes/api.php b/Modules/Client/Routes/api.php index 6fb49e19..724ce079 100644 --- a/Modules/Client/Routes/api.php +++ b/Modules/Client/Routes/api.php @@ -18,6 +18,7 @@ use Modules\Internal\Http\Controllers\Api\FormulariumController; use Modules\Internal\Http\Controllers\Api\FormulariumTemplateController; use Modules\Internal\Http\Controllers\Api\AuditTrailController; use Modules\Internal\Http\Controllers\Api\CorporateController; +use Modules\Internal\Http\Controllers\Api\NavigationController; /* |-------------------------------------------------------------------------- @@ -70,6 +71,7 @@ Route::prefix('client')->group(function () { Route::get('corporate', [CorporateCurrentController::class, 'index']); Route::put('corporate-update', [CorporateCurrentController::class, 'update']); + Route::get('get-deposits', [CorporateMemberController::class, 'getDeposit']); }); Route::get('claims/{id}', [ClaimController::class, 'show']); @@ -90,5 +92,8 @@ Route::prefix('client')->group(function () { Route::get('audittrail/{corporate_id}', [AuditTrailController::class, 'index']); Route::get('corporates/import-document-example/{document_type}', [CorporateController::class, 'importDocumentExample']); + + // Navigation + Route::get('navigations', [NavigationController::class, 'index']); }); }); diff --git a/database/seeders/NavigationSeeder.php b/database/seeders/NavigationSeeder.php index d2627976..dca07167 100644 --- a/database/seeders/NavigationSeeder.php +++ b/database/seeders/NavigationSeeder.php @@ -27,12 +27,12 @@ class NavigationSeeder extends Seeder 'title' => 'DOCTORS & HOSPITALS', 'children' => [ [ - 'title' => 'Doctors', - 'path' => '/master/doctors', + 'title' => 'Doctors', + 'path' => '/master/doctors', 'permission' => 'doctor-list' ], [ - 'title' => 'Hospitals', + 'title' => 'Hospitals', 'path' => '/master/hospitals', 'permission' => 'hospital-list' ], @@ -44,17 +44,17 @@ class NavigationSeeder extends Seeder 'title' => 'PHARMACY & DELIVERY MANAGEMENT', 'children' => [ [ - 'title' => 'Drug', + 'title' => 'Drug', 'path' => '/master/drugs', 'permission' => 'drug-list' ], [ - 'title' => 'Inventory', + 'title' => 'Inventory', 'path' => '/inventory', 'permission' => null ], [ - 'title' => 'Delivery Services', + 'title' => 'Delivery Services', 'path' => '/delivery', 'permission' => null ], @@ -67,23 +67,23 @@ class NavigationSeeder extends Seeder 'openWhen' => ['/corporates', '/formularium', '/diagnosis', '/hospitals'], 'children' => [ [ - 'title' => 'Corporate', + 'title' => 'Corporate', 'path' => '/corporates', 'permission' => 'corporate-list', ], // ['title' => 'Corporate Create', 'path' => '/corporates/create'], [ - 'title' => 'Formularium', + 'title' => 'Formularium', 'path' => '/master/formularium-template-v2', 'permission' => 'formularium-list', ], [ - 'title' => 'Master ICD-10 Diagnosis', + 'title' => 'Master ICD-10 Diagnosis', 'path' => '/master/diagnosis', 'permission' => 'diagnosis-list', ], [ - 'title' => 'Hospitals', + 'title' => 'Hospitals', 'path' => '/hospitals', 'permission' => null, ], @@ -92,13 +92,13 @@ class NavigationSeeder extends Seeder ], // CLAIM REQUEST [ - 'title' => 'CLAIM REQUEST', + 'title' => 'CLAIM REQUEST', 'path' => '/claim-requests', 'permission' => 'claim-request-list' ], // CLAIM MANAGEMENT [ - 'title' => 'CLAIM MANAGEMENT', + 'title' => 'CLAIM MANAGEMENT', 'path' => '/claims', 'permission' => 'claim-management-list' ], @@ -107,13 +107,13 @@ class NavigationSeeder extends Seeder 'title' => 'CASE MANAGEMENT', 'children' => [ [ - 'title' => 'Daily Monitoring', + 'title' => 'Daily Monitoring', 'path' => '/case_management/daily_monitoring', 'permission' => 'daily-monitoring-list' ], // ['title' => 'Laboratorium Result', 'path' => '/case_management/laboratorium_result'], [ - 'title' => 'Inpatient Monitoring', + 'title' => 'Inpatient Monitoring', 'path' => '/case_management/inpatient_monitoring', 'permission' => 'final-log-list' ], @@ -125,13 +125,13 @@ class NavigationSeeder extends Seeder 'title' => 'CUSTOMER SERVICES', 'children' => [ [ - 'title' => 'Request', + 'title' => 'Request', 'path' => '/custormer-service/request', 'permission' => 'request-log-list' ], // ['title' => 'Membership', 'path' => '/cs-membership'], [ - 'title' => 'Final LOG', + 'title' => 'Final LOG', 'path' => '/custormer-service/final-log', 'permission' => 'final-log-list' ], @@ -143,33 +143,33 @@ class NavigationSeeder extends Seeder 'title' => 'REPORT', 'children' => [ [ - 'title' => 'Files Provider', + 'title' => 'Files Provider', 'path' => 'report/files-provider', 'permission' => 'report-files-provider-list' ], [ - 'title' => 'Letter of Guarantee', + 'title' => 'Letter of Guarantee', 'path' => '/report/logs', 'permission' => 'report-log-list' ], [ - 'title' => 'Appointment', + 'title' => 'Appointment', 'path' => '/report/appointments', 'permission' => 'report-appointment-list' ], [ - 'title' => 'Live Chat', + 'title' => 'Live Chat', 'path' => '/report/live-chat', 'permission' => 'report-livechat-list' ], [ - 'title' => 'Linksehat Payment', + 'title' => 'Linksehat Payment', 'path' => '/report/linksehat-payments', 'permission' => 'report-livechat-payment' ], // ['title' => 'Prescription', 'path' => '/report/prescription'], [ - 'title' => 'Doctor Rating', + 'title' => 'Doctor Rating', 'path' => '/report/doctorrating', 'permission' => 'report-doctor-rating' ], @@ -181,7 +181,7 @@ class NavigationSeeder extends Seeder 'title' => 'MASTER', 'children' => [ [ - 'title' => 'Diagnosis', + 'title' => 'Diagnosis', 'path' => '/master/diagnosis', 'permission' => 'diagnosis-list' ], @@ -193,12 +193,12 @@ class NavigationSeeder extends Seeder 'title' => 'USER MANAGEMENT', 'children' => [ [ - 'title' => 'User Role', + 'title' => 'User Role', 'path' => '/user-role', 'permission' => 'user-role-list' ], [ - 'title' => 'User Access', + 'title' => 'User Access', 'path' => '/user-access', 'permission' => 'user-access-list' ], @@ -207,21 +207,66 @@ class NavigationSeeder extends Seeder ], // LINKING TOOLS [ - 'title' => 'LINKING TOOLS', + 'title' => 'LINKING TOOLS', 'path' => '/linking', 'permission' => 'linkking-list' ], // E-PRESCRIPTION [ - 'title' => 'E-PRESCRIPTION', + 'title' => 'E-PRESCRIPTION', 'path' => '/e-prescription/live-chat', 'permission' => 'prescription-list' ], + ####################### CLIENT PORTAL ######################### + [ + 'title' => 'Dashboard', + 'children' => [ + [ + 'title' => 'Usage Dashboard', + 'path' => '/dashboard', + 'permission' => 'dashboard-list-client-portal' + ], + ], + 'permission' => 'dashboard-client-portal' + ], + [ + 'title' => 'Corporate', + 'children' => [ + [ + 'title' => 'Corporate', + 'path' => '/corporate', + 'permission' => 'corporate-list-client-portal' + ], + [ + 'title' => 'Employee Data', + 'path' => '/employee-data', + 'permission' => 'employee-data-list-client-portal' + ], + ], + 'permission' => 'corporate-client-portal' + ], + [ + 'title' => 'Case Management', + 'children' => [ + [ + 'title' => 'Alarm Center', + 'path' => '/alarm-center', + 'permission' => 'alarm-center-list-client-portal' + ], + [ + 'title' => 'Formularium', + 'path' => '/master/formularium-template-v2', + 'permission' => 'formularium-list-client-portal' + ], + ], + 'permission' => 'case-management-client-portal' + ], ]; foreach ($menuItems as $menuItemData) { $menuItem = Navigations::updateOrCreate([ - 'title' => $menuItemData['title'] + 'title' => $menuItemData['title'], + 'permission' => $menuItemData['permission'] ], [ 'title' => $menuItemData['title'], diff --git a/database/seeders/PermissionTableSeeder.php b/database/seeders/PermissionTableSeeder.php index a96d4894..bbcdcf89 100644 --- a/database/seeders/PermissionTableSeeder.php +++ b/database/seeders/PermissionTableSeeder.php @@ -17,65 +17,86 @@ class PermissionTableSeeder extends Seeder public function run() { $permissions = [ - 'dashboard', - 'doctor-list', - 'doctor-create', - 'doctor-edit', - 'doctor-delete', - 'hospital-list', - 'hospital-create', - 'hospital-edit', - 'hospital-delete', - 'drug-list', - 'drug-create', - 'drug-edit', - 'drug-delete', - 'corporate-list', - 'corporate-create', - 'corporate-edit', - 'corporate-delete', - 'formularium-list', - 'formularium-create', - 'formularium-edit', - 'formularium-delete', - 'diagnosis-list', - 'diagnosis-create', - 'diagnosis-edit', - 'diagnosis-delete', - 'claim-request-list', - 'claim-request-create', - 'claim-request-edit', - 'claim-request-delete', - 'claim-management-list', - 'claim-management-create', - 'claim-management-edit', - 'claim-management-delete', - 'daily-monitoring-list', - 'request-log-list', - 'request-log-create', - 'request-log-edit', - 'request-log-delete', - 'final-log-list', - 'final-log-create', - 'final-log-edit', - 'final-log-delete', - 'report-files-provider-list', - 'report-letter-of-guarante-list', - 'report-log-list', - 'report-appointment-list', - 'report-livechat-list', - 'report-livechat-payment', - 'report-doctor-rating', - 'user-role-list', - 'user-access-list' + [ + 'type' => 'web', + 'datas' => [ + 'dashboard', + 'doctor-list', + 'doctor-create', + 'doctor-edit', + 'doctor-delete', + 'hospital-list', + 'hospital-create', + 'hospital-edit', + 'hospital-delete', + 'drug-list', + 'drug-create', + 'drug-edit', + 'drug-delete', + 'corporate-list', + 'corporate-create', + 'corporate-edit', + 'corporate-delete', + 'formularium-list', + 'formularium-create', + 'formularium-edit', + 'formularium-delete', + 'diagnosis-list', + 'diagnosis-create', + 'diagnosis-edit', + 'diagnosis-delete', + 'claim-request-list', + 'claim-request-create', + 'claim-request-edit', + 'claim-request-delete', + 'claim-management-list', + 'claim-management-create', + 'claim-management-edit', + 'claim-management-delete', + 'daily-monitoring-list', + 'request-log-list', + 'request-log-create', + 'request-log-edit', + 'request-log-delete', + 'final-log-list', + 'final-log-create', + 'final-log-edit', + 'final-log-delete', + 'report-files-provider-list', + 'report-letter-of-guarante-list', + 'report-log-list', + 'report-appointment-list', + 'report-livechat-list', + 'report-livechat-payment', + 'report-doctor-rating', + 'user-role-list', + 'user-access-list' + ] + ], + ####################### CLIENT PORTAL ######################### + [ + 'type' => 'client-portal', + 'datas' => [ + 'dashboard-client-portal', + 'dashboard-list-client-portal', + 'corporate-list-client-portal', + 'employee-data-list-client-portal', + 'corporate-client-portal', + 'alarm-center-list-client-portal', + 'formularium-list-client-portal', + 'case-management-client-portal' + ] + ] ]; - foreach ($permissions as $permission) { - Permission::updateOrCreate(['name' => $permission], - [ - 'name' => $permission, - 'guard_name' => 'web' - ]); + foreach ($permissions as $values) { + foreach ($values['datas'] as $value) { + Permission::updateOrCreate(['name' => $value], + [ + 'name' => $value, + 'guard_name' => $values['type'] + ]); + } } } } diff --git a/frontend/client-portal/src/components/nav-section/vertical/index.tsx b/frontend/client-portal/src/components/nav-section/vertical/index.tsx index 41f0b915..de247933 100644 --- a/frontend/client-portal/src/components/nav-section/vertical/index.tsx +++ b/frontend/client-portal/src/components/nav-section/vertical/index.tsx @@ -32,18 +32,16 @@ export default function NavSectionVertical({ {navConfig.map((group, index) => ( - {group.subheader && ( - - {group.subheader} - - )} + + {group.subheader} + {group.items.map((list) => ( diff --git a/frontend/client-portal/src/layouts/dashboard/navbar/NavbarVertical.tsx b/frontend/client-portal/src/layouts/dashboard/navbar/NavbarVertical.tsx index f4002fa0..cd52fd1b 100644 --- a/frontend/client-portal/src/layouts/dashboard/navbar/NavbarVertical.tsx +++ b/frontend/client-portal/src/layouts/dashboard/navbar/NavbarVertical.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; // @mui import { styled, useTheme } from '@mui/material/styles'; @@ -15,9 +15,11 @@ import Logo from '../../../components/Logo'; import Scrollbar from '../../../components/Scrollbar'; import { NavSectionVertical } from '../../../components/nav-section'; // -import navConfig from './NavConfig'; +// import navConfig from './NavConfig'; import NavbarAccount from './NavbarAccount'; import CollapseButton from './CollapseButton'; +import useAuth from '@/hooks/useAuth'; +import axios from '@/utils/axios'; // ---------------------------------------------------------------------- @@ -42,10 +44,54 @@ export default function NavbarVertical({ isOpenSidebar, onCloseSidebar }: Props) const { pathname } = useLocation(); + const {user} = useAuth() + const isDesktop = useResponsive('up', 'lg'); const { isCollapse, collapseClick, collapseHover, onToggleCollapse, onHoverEnter, onHoverLeave } = useCollapseDrawer(); + const [navConfig, setNavConfig] = useState([]); + useEffect(() => { + const fetchNavConfig = async () => { + try { + const response = await axios.get('/navigations'); + const data = response.data.items; + + // Pastikan user dan user.permissions terdefinisi dan merupakan array + const userPermissions = user.user?.permissions?.map(permission => permission.name) || []; + + // Fungsi untuk memeriksa apakah pengguna memiliki izin untuk item tertentu + const hasPermission = (permission) => { + return userPermissions.includes(permission); + }; + + // Filter data berdasarkan izin pengguna + const filteredNavConfig = data.map(section => { + if (section.children && section.children.length > 0) { + // Cek apakah ada satu atau lebih children yang memiliki izin + const filteredChildren = section.children.filter(child => hasPermission(child.permission)); + + if (filteredChildren.length > 0) { + return { + ...section, + children: filteredChildren + }; + } else { + return null; // Lewati bagian yang tidak memiliki children dengan izin + } + } + // Jika tidak ada children, cek izin untuk section itu sendiri + return hasPermission(section.permission) ? section : null; + }).filter(section => section !== null); + + setNavConfig([{ items: filteredNavConfig }]); + } catch (error) { + console.error('Gagal mengambil konfigurasi navigasi:', error); + } + }; + + fetchNavConfig(); + }, [user]); useEffect(() => { if (isOpenSidebar) { diff --git a/frontend/client-portal/src/pages/Dashboard/Index.tsx b/frontend/client-portal/src/pages/Dashboard/Index.tsx index ac304f66..8fe9f540 100644 --- a/frontend/client-portal/src/pages/Dashboard/Index.tsx +++ b/frontend/client-portal/src/pages/Dashboard/Index.tsx @@ -1,276 +1,130 @@ // @mui -import { Typography, Container, Grid, Button, SelectChangeEvent } from '@mui/material'; +import { CardContent,Button, Container, Grid, styled, Typography, Card, Stack } from '@mui/material'; // hooks import useSettings from '../../hooks/useSettings'; // components import Page from '../../components/Page'; -// theme -import { useContext, useEffect, useState } from 'react'; import axios from '../../utils/axios'; -import { Stack } from '@mui/system'; +import useAuth from '../../hooks/useAuth'; +import SomethingUsage from '../../sections/dashboard/SomethingUsage'; +import { fCurrency } from '../../utils/formatNumber'; +import AccountBalanceWalletIcon from '@mui/icons-material/AccountBalanceWallet'; +import TrendingUpIcon from '@mui/icons-material/TrendingUp'; +import MonetizationOnIcon from '@mui/icons-material/MonetizationOn'; +import { useContext, useEffect, useState } from 'react'; + import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; -import Table from '../../components/Table'; -import { HeadCell, Order, PaginationTableProps } from '../../@types/table'; -import { useSearchParams } from 'react-router-dom'; -import palette from '../../theme/palette'; -export default function Index() { +// ---------------------------------------------------------------------- + +export default function Dashboard() { const { themeStretch } = useSettings(); - const { corporateValue } = useContext(UserCurrentCorporateContext); - const controller = new AbortController(); - const [memberData, setMemberData] = useState([]); + const { logout } = useAuth(); - /* -------------------------------------------------------------------------- */ - /* setting up for the table */ - /* -------------------------------------------------------------------------- */ - const [isLoading, setIsLoading] = useState(true); - - const loadings = { - isLoading: isLoading, - setIsLoading: setIsLoading, + const loadSomething = () => { + axios.get('/user') }; - /* ------------------------------ handle params ----------------------------- */ - const [searchParams, setSearchParams] = useSearchParams(); - const [appliedParams, setAppliedParams] = useState({}); + const Wallet = styled(AccountBalanceWalletIcon)(({ theme }) => ({ + color: 'orange', + marginRight: theme.spacing(1), + })); - const params = { - searchParams: searchParams, - setSearchParams: setSearchParams, - appliedParams: appliedParams, - setAppliedParams: setAppliedParams, - }; - /* -------------------------------------------------------------------------- */ + const TrendUp = styled(TrendingUpIcon)(({ theme }) => ({ + color: 'blue', + marginRight: theme.spacing(1), + })); - /* ------------------------------ handle order ------------------------------ */ - const [order, setOrder] = useState('asc'); - const [orderBy, setOrderBy] = useState('fullName'); + const Monet = styled(MonetizationOnIcon)(({ theme }) => ({ + color: 'orange', + marginRight: theme.spacing(1), + })); - const orders = { - order: order, - setOrder: setOrder, - orderBy: orderBy, - setOrderBy: setOrderBy, - }; - /* -------------------------------------------------------------------------- */ + const DangerCard = styled(Card)(({ theme }) => ({ + boxShadow: 'none', + padding: theme.spacing(3), + color: theme.palette.error.main, + backgroundColor: theme.palette.error.lighter, + })); - /* ---------------------------- handle pagination --------------------------- */ - const [page, setPage] = useState(0); - const [rowsPerPage, setRowsPerPage] = useState(10); + const SuccessCard = styled(Card)(({ theme }) => ({ + boxShadow: 'none', + padding: theme.spacing(3), + color: theme.palette.success.darker, + backgroundColor: theme.palette.success.lighter, + })); - const [paginationTable, setPaginationTable] = useState({ - current_page: 0, - from: 0, - last_page: 0, - links: [], - path: '', - per_page: 0, - to: 0, - total: 0, - }); + const DefaultCard = styled(Card)(({ theme }) => ({ + boxShadow: theme.shadows[3], // Menggunakan bayangan standar dari tema + padding: theme.spacing(3), + color: theme.palette.text.primary, + backgroundColor: theme.palette.background.paper, // Latar belakang putih +})); +const { corporateValue } = useContext(UserCurrentCorporateContext); - const paginations = { - page: page, - setPage: setPage, - rowsPerPage: rowsPerPage, - setRowsPerPage: setRowsPerPage, - paginationTable: paginationTable, - setPaginationTable: setPaginationTable, - }; - /* -------------------------------------------------------------------------- */ +const [depositData, setDepositData] = useState({ deposit: 0, limit: 0, usage: 0 }); - /* ------------------------------ handle search ----------------------------- */ - const [searchText, setSearchText] = useState(''); + useEffect(() => { + const fetchDepositData = async () => { + try { + const response = await axios.get(`${corporateValue}/get-deposits`); + setDepositData(response.data); + } catch (error) { + console.error('Failed to fetch deposit data:', error); + } + }; - 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, - }; - /* -------------------------------------------------------------------------- */ - - /* ------------------------------ handle filter ----------------------------- */ - 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); - } - }; - - const filters = { - useFilter: true, - config: { - label: 'Division', - divisionValue: divisionValue, - divisionData: divisionData, - handleDivisionChange: handleDivisionChange, - }, - }; - /* -------------------------------------------------------------------------- */ - - /* -------------------------------- headCell -------------------------------- */ - const headCells: HeadCell[] = [ - { - 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: 'status', - align: 'center', - label: 'Status', - isSort: true, - }, - { - id: 'action', - align: 'right', - label: '', - isSort: false, - }, - ]; - /* -------------------------------------------------------------------------- */ - - useEffect(() => { - (async () => { - try { - setIsLoading(true); - - const parameters = - Object.keys(appliedParams).length !== 0 - ? appliedParams - : Object.fromEntries([ - ...searchParams.entries(), - ['order', order], - ['orderBy', orderBy], - ]); - - const [divisionResponse, membersResponse] = await Promise.all([ - axios.get(`${corporateValue}/division`, { signal: controller.signal }), - axios.get(`${corporateValue}/members`, { - params: { ...parameters }, - signal: controller.signal, - }), - ]); - - setSearchParams(parameters); - setDivisionData(divisionResponse.data); - setMemberData( - membersResponse.data.data.map((obj: any) => ({ - ...obj, - status: - obj.status === 1 ? ( - - ) : ( - - ), - })) - ); - setPaginationTable(membersResponse.data); - setRowsPerPage(membersResponse.data.per_page); - - if (searchParams.get('page')) { - // @ts-ignore - const currentPage = parseInt(searchParams.get('page')) - 1; - paginationTable.current_page = currentPage; - setPage(currentPage); - } - - setIsLoading(false); - } catch (error: any) { - console.error('Error fetching data:', error.message); - } - })(); - - return () => { - controller.abort(); - }; - }, [appliedParams, searchParams, order, orderBy, setSearchParams, corporateValue]); + fetchDepositData(); + }, [corporateValue]); return ( - - - Dashboard - - + + Dashboard + - - + + {/* */} + + + + + {fCurrency(depositData.deposit)} + + + Deposit + + + + + + + + + + {fCurrency(depositData.limit)} + + + Limit + + + + + + + + + + {fCurrency(depositData.usage)} + + + This Year Usage + + + diff --git a/frontend/client-portal/src/pages/Dashboard/Index_.tsx b/frontend/client-portal/src/pages/Dashboard/Index_.tsx new file mode 100644 index 00000000..3bf07784 --- /dev/null +++ b/frontend/client-portal/src/pages/Dashboard/Index_.tsx @@ -0,0 +1,279 @@ +// @mui +import { Typography, Container, Grid, Button, SelectChangeEvent } from '@mui/material'; +// hooks +import useSettings from '../../hooks/useSettings'; +// components +import Page from '../../components/Page'; +// theme +import { useContext, useEffect, useState } from 'react'; +import axios from '../../utils/axios'; +import { Stack } from '@mui/system'; +import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; +import Table from '../../components/Table'; +import { HeadCell, Order, PaginationTableProps } from '../../@types/table'; +import { useSearchParams } from 'react-router-dom'; +import palette from '../../theme/palette'; + +export default function Index_() { + const { themeStretch } = useSettings(); + const { corporateValue } = useContext(UserCurrentCorporateContext); + const controller = new AbortController(); + + const [memberData, setMemberData] = 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, + }; + /* -------------------------------------------------------------------------- */ + + /* ------------------------------ handle filter ----------------------------- */ + 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); + } + }; + + const filters = { + useFilter: true, + config: { + label: 'Division', + divisionValue: divisionValue, + divisionData: divisionData, + handleDivisionChange: handleDivisionChange, + }, + }; + /* -------------------------------------------------------------------------- */ + + /* -------------------------------- headCell -------------------------------- */ + const headCells: HeadCell[] = [ + { + 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: 'status', + align: 'center', + label: 'Status', + isSort: true, + }, + { + id: 'action', + align: 'right', + label: '', + isSort: false, + }, + ]; + /* -------------------------------------------------------------------------- */ + + useEffect(() => { + (async () => { + try { + setIsLoading(true); + + const parameters = + Object.keys(appliedParams).length !== 0 + ? appliedParams + : Object.fromEntries([ + ...searchParams.entries(), + ['order', order], + ['orderBy', orderBy], + ]); + + const [divisionResponse, membersResponse] = await Promise.all([ + axios.get(`${corporateValue}/division`, { signal: controller.signal }), + axios.get(`${corporateValue}/members`, { + params: { ...parameters }, + signal: controller.signal, + }), + ]); + + setSearchParams(parameters); + setDivisionData(divisionResponse.data); + setMemberData( + membersResponse.data.data.map((obj: any) => ({ + ...obj, + status: + obj.status === 1 ? ( + + ) : ( + + ), + })) + ); + setPaginationTable(membersResponse.data); + setRowsPerPage(membersResponse.data.per_page); + + if (searchParams.get('page')) { + // @ts-ignore + const currentPage = parseInt(searchParams.get('page')) - 1; + paginationTable.current_page = currentPage; + setPage(currentPage); + } + + setIsLoading(false); + } catch (error: any) { + console.error('Error fetching data:', error.message); + } + })(); + + return () => { + controller.abort(); + }; + }, [appliedParams, searchParams, order, orderBy, setSearchParams, corporateValue]); + + return ( + + + + + Dashboard + + + + + +
+ + + + + ); +} diff --git a/frontend/client-portal/src/sections/dashboard/SomethingUsage.tsx b/frontend/client-portal/src/sections/dashboard/SomethingUsage.tsx new file mode 100644 index 00000000..4fbaafc3 --- /dev/null +++ b/frontend/client-portal/src/sections/dashboard/SomethingUsage.tsx @@ -0,0 +1,80 @@ +import merge from 'lodash/merge'; +import ReactApexChart from 'react-apexcharts'; +// @mui +import { styled } from '@mui/material/styles'; +import { Card, Typography, Stack } from '@mui/material'; +// utils +import { fCurrency, fPercent } from '../../utils/formatNumber'; +// components +import Iconify from '../../components/Iconify'; +import BaseOptionChart from '../../components/chart/BaseOptionChart'; + +// ---------------------------------------------------------------------- + +const RootStyle = styled(Card)(({ theme }) => ({ + boxShadow: 'none', + padding: theme.spacing(3), + color: theme.palette.primary.darker, + backgroundColor: theme.palette.primary.lighter, +})); + +// ---------------------------------------------------------------------- + +const INITIAL = 500000000 +const TOTAL = 257907000; +const PERCENT = -3; +const CHART_DATA = [{ data: [100, 99, 99, 85, 74, 57, 54, 51] }]; + +export default function SomethingUsage() { + const chartOptions = merge(BaseOptionChart(), { + chart: { sparkline: { enabled: true } }, + xaxis: { labels: { show: true } }, + yaxis: { labels: { show: false } }, + stroke: { width: 4 }, + legend: { show: false }, + grid: { show: false }, + tooltip: { + marker: { show: false }, + y: { + formatter: (seriesName: string) => (seriesName) + "%", + title: { + formatter: () => '', + }, + }, + }, + fill: { gradient: { opacityFrom: 0, opacityTo: 0 } }, + }); + + return ( + + +
+ + {fCurrency(INITIAL)} + + Remaining Balance + {fCurrency(TOTAL)} +
+ +
+ + = 0 ? 'eva:trending-up-fill' : 'eva:trending-down-fill'} + /> + + {PERCENT > 0 && '+'} + {fPercent(PERCENT)} + + + +  than last month + +
+
+ + +
+ ); +} From 4ab48219abc96c3faeacb5ff13e629788a867b0f Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Tue, 18 Jun 2024 16:38:06 +0700 Subject: [PATCH 03/13] Update --- .../Api/CorporateMemberController.php | 46 ++++++ Modules/Client/Routes/api.php | 2 + .../AlarmCenter/DataServiceMonitoring.php | 19 +-- database/seeders/PermissionTableSeeder.php | 3 +- .../pages/AlarmCenter/ServiceMonitoring.tsx | 132 +++++++++++++---- .../src/pages/Dashboard/Index.tsx | 136 ++++++++++++------ 6 files changed, 253 insertions(+), 85 deletions(-) diff --git a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php index dd0832f7..5275fb01 100644 --- a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php +++ b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php @@ -277,4 +277,50 @@ class CorporateMemberController extends Controller return response()->json($deposit); } + + public function getLimits($corporate_id, $member_id) + { + $deposit = DB::table('corporate_policies') + ->select('total_premi') + ->where('corporate_id','=', $corporate_id) + ->first(); + $usage = DB::table('corporate_employees') + ->join('request_logs', 'request_logs.member_id', '=', 'corporate_employees.member_id') + ->join('request_log_benefits', 'request_log_benefits.request_log_id', '=', 'request_logs.id') + ->where('corporate_employees.corporate_id', '=', $corporate_id) + ->where('request_logs.member_id', '=', $member_id) + ->sum('request_log_benefits.amount_approved'); + + $services = DB::table('member_plans') + ->leftJoin('plans', 'plans.id', '=', 'member_plans.plan_id') + ->leftJoin('services', 'services.code', '=', 'plans.service_code') + ->where('member_plans.member_id', '=', $member_id) + ->whereNull('member_plans.deleted_at') + ->select( + 'plans.service_code', + 'services.name as title', + 'plans.limit_rules as total', + DB::raw(" + ( + SELECT SUM(request_log_benefits.amount_approved) + FROM request_logs + INNER JOIN request_log_benefits + ON request_log_benefits.request_log_id = request_logs.id + WHERE request_logs.member_id = $member_id + AND request_logs.service_code = plans.service_code + ) as current + ") + + ) + ->get(); + // Ganti dengan logika Anda untuk mendapatkan data deposit + $deposit = [ + 'deposit' => $deposit->total_premi, + 'usage' => $usage, + 'services' => $services + ]; + + return response()->json($deposit); + } + } diff --git a/Modules/Client/Routes/api.php b/Modules/Client/Routes/api.php index 724ce079..090e2cd4 100644 --- a/Modules/Client/Routes/api.php +++ b/Modules/Client/Routes/api.php @@ -72,6 +72,8 @@ Route::prefix('client')->group(function () { Route::get('corporate', [CorporateCurrentController::class, 'index']); Route::put('corporate-update', [CorporateCurrentController::class, 'update']); Route::get('get-deposits', [CorporateMemberController::class, 'getDeposit']); + + Route::get('get-limits/{member_id}', [CorporateMemberController::class, 'getLimits']); }); Route::get('claims/{id}', [ClaimController::class, 'show']); diff --git a/Modules/Client/Transformers/AlarmCenter/DataServiceMonitoring.php b/Modules/Client/Transformers/AlarmCenter/DataServiceMonitoring.php index caaaeaef..1028409f 100644 --- a/Modules/Client/Transformers/AlarmCenter/DataServiceMonitoring.php +++ b/Modules/Client/Transformers/AlarmCenter/DataServiceMonitoring.php @@ -23,11 +23,11 @@ class DataServiceMonitoring extends JsonResource $filesFinalLogKondisi = []; if (count($this->files)>0){ foreach ($this->files as $key => $value) { - /* - Sementara di buat satu dulu, jangan di hapus.. + /* + Sementara di buat satu dulu, jangan di hapus.. karena suka labil client nya, tiba2 hide tiba2 munculin fitur :D */ - + // if($value->type == 'final-log-result'){ array_push($filesFinalLogResult, $value); // }; @@ -71,7 +71,7 @@ class DataServiceMonitoring extends JsonResource $main_diagnosis = $d; } $diagnosis = '-'; - } + } if ($key > 0){ if ($icd) { @@ -86,6 +86,7 @@ class DataServiceMonitoring extends JsonResource return [ 'companyName' => $this->member->currentCorporate->name ?? null, 'serviceCode' => $this->service_code ?? null, + 'member_id' => $this->member->id ?? null, 'memberId' => $this->member->member_id ?? null, 'fullName' => $this->member->full_name ?? null, 'dateOfBirth' => $this->member->birth_date ?? null, @@ -121,7 +122,7 @@ class DataServiceMonitoring extends JsonResource $arr_document = []; $document = DB::table('files') ->where([ - 'fileable_type' => 'App\Models\LaboratoriumResult', + 'fileable_type' => 'App\Models\LaboratoriumResult', 'fileable_id' => $requestLogDailyMonitoring->id, 'deleted_at' => null ]) @@ -138,7 +139,7 @@ class DataServiceMonitoring extends JsonResource } } - + return [ 'time' => Carbon::parse($requestLogDailyMonitoring->submission_date)->format('H:i') ?? null, 'status' => 'Done' ?? null, @@ -180,12 +181,12 @@ class DataServiceMonitoring extends JsonResource }) ->map(function ($groupedItems) { return collect($groupedItems) - + ->map(function ($test) { $arr_document = []; $document = DB::table('files') ->where([ - 'fileable_type' => 'App\Models\LaboratoriumResult', + 'fileable_type' => 'App\Models\LaboratoriumResult', 'fileable_id' => $test->id, 'deleted_at' => null ]) @@ -201,7 +202,7 @@ class DataServiceMonitoring extends JsonResource ]; } } - + return [ 'code' => $test->code, 'date' => Carbon::parse($test->lab_date)->format('d M Y') ?? null, diff --git a/database/seeders/PermissionTableSeeder.php b/database/seeders/PermissionTableSeeder.php index bbcdcf89..fa57a98e 100644 --- a/database/seeders/PermissionTableSeeder.php +++ b/database/seeders/PermissionTableSeeder.php @@ -84,7 +84,8 @@ class PermissionTableSeeder extends Seeder 'corporate-client-portal', 'alarm-center-list-client-portal', 'formularium-list-client-portal', - 'case-management-client-portal' + 'case-management-client-portal', + 'service-monitoring-limit-client-portal', ] ] ]; diff --git a/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx b/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx index 449f036c..b911d7d8 100644 --- a/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx +++ b/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx @@ -20,11 +20,14 @@ import { ListItemText, ListItemButton, Divider, + CardContent, + LinearProgress } from '@mui/material'; import { styled } from '@mui/material/styles'; import { Download as DownloadIcon, Circle as CircleIcon, TableView } from '@mui/icons-material'; // components import Page from '../../components/Page'; +import { fCurrency } from '../../utils/formatNumber'; // utils import { useState, SyntheticEvent, useContext, useEffect } from 'react'; import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; @@ -45,6 +48,8 @@ import TableMoreMenu from '../../components/table/TableMoreMenu'; import Label from '../../components/Label'; import { fSplit } from '../../utils/formatNumber'; +import useAuth from '../../hooks/useAuth'; + interface TabPanelProps { children?: React.ReactNode; index: number; @@ -208,6 +213,13 @@ type ServiceMonitoringProps = { }; export default function ServiceMonitoring() { + const {user} = useAuth(); + const checkIfNameExists = (name) => { + return user.user.permissions.some(item => item.name === name); + }; + + const nameToCheck = 'service-monitoring-limit-client-porta'; + const doesNameExist = checkIfNameExists(nameToCheck); const navigate = useNavigate(); const controller = new AbortController(); @@ -221,7 +233,7 @@ export default function ServiceMonitoring() { const { corporateValue } = useContext(UserCurrentCorporateContext); const { memberId, requestLogId } = useParams(); - + const [depositData, setDepositData] = useState({ deposit: 0, limit: 0, usage: 0 }); useEffect(() => { (async () => { try { @@ -236,6 +248,18 @@ export default function ServiceMonitoring() { if (response.data.data.serviceCode !== 'IP') { setValue(1); } + + var member_id = response.data.data.member_id; + const fetchDepositData = async () => { + try { + const response = await axios.get(`${corporateValue}/get-limits/${member_id}`); + setDepositData(response.data); + } catch (error) { + console.error('Failed to fetch deposit data:', error); + } + }; + + fetchDepositData(); } catch (error: any) { console.error('Error fetching data:', error.message); } finally { @@ -248,7 +272,7 @@ export default function ServiceMonitoring() { }; }, [corporateValue]); - + const renderHTML = (data:string) => { return (
); } + const formatNumber = (number) => { + return new Intl.NumberFormat('id-ID').format(number); + }; + const LimitPlanCard = ({ title, current, total }) => ( + + + + {title} + + + Yearly Limits + + + {formatNumber(current)} / {formatNumber(total)} + + + + + ); + const plans = [ + { title: 'Outpatient', current: 200000, total: 1000000 }, + { title: 'Inpatient', current: 1000000, total: 5000000 }, + { title: 'Dental', current: 250000, total: 1000000 }, + { title: 'Maternity', current: 0, total: 3000000 }, + ]; return ( @@ -277,14 +326,14 @@ export default function ServiceMonitoring() { - - - {loading ? : 'Employee Profile'} - - - + - + + + {loading ? : 'Employee Profile'} + + + {loading ? : 'Company Name'} @@ -300,8 +349,6 @@ export default function ServiceMonitoring() { )} - - {loading ? : 'Member ID'} @@ -318,8 +365,6 @@ export default function ServiceMonitoring() { )} - - {loading ? : 'Full Name'} @@ -336,8 +381,6 @@ export default function ServiceMonitoring() { )} - - {loading ? : 'Date of Birth'} @@ -354,8 +397,6 @@ export default function ServiceMonitoring() { )} - - {loading ? : 'Phone Number'} @@ -372,8 +413,6 @@ export default function ServiceMonitoring() { )} - - {loading ? : 'Email'} @@ -391,6 +430,43 @@ export default function ServiceMonitoring() { + + {doesNameExist ? ( + + + + + + Limit + + + Yearly Limits + + + {formatNumber(depositData.usage)} / {formatNumber(depositData.deposit)} + + + + + + + + Limit Plan + + + {depositData.services?.map((plan) => ( + + ))} + + + + ) : ''} + @@ -400,7 +476,7 @@ export default function ServiceMonitoring() { - + @@ -501,9 +577,9 @@ export default function ServiceMonitoring() { {loading ? ( - ) : data && data.files && data.files.result.length > 0 ? + ) : data && data.files && data.files.result.length > 0 ? ( - data.files.result.map((file, index) => + data.files.result.map((file, index) => ( ( @@ -539,9 +615,9 @@ export default function ServiceMonitoring() { {loading ? ( - ) : data && data.files && data.files.diagnosis.length > 0 ? + ) : data && data.files && data.files.diagnosis.length > 0 ? ( - data.files.diagnosis.map((file, index) => + data.files.diagnosis.map((file, index) => ( ( @@ -577,9 +653,9 @@ export default function ServiceMonitoring() { {/* {loading ? ( - ) : data && data.files && data.files.kondisi.length > 0 ? + ) : data && data.files && data.files.kondisi.length > 0 ? ( - data.files.kondisi.map((file, index) => + data.files.kondisi.map((file, index) => ( ( @@ -1180,7 +1256,7 @@ export default function ServiceMonitoring() { {file.original_name} - ) + ) ) ) : (
  • -
  • @@ -1259,7 +1335,7 @@ export default function ServiceMonitoring() { {file.original_name} - ) + ) ) ) : (
  • -
  • diff --git a/frontend/client-portal/src/pages/Dashboard/Index.tsx b/frontend/client-portal/src/pages/Dashboard/Index.tsx index 8fe9f540..8bae1f72 100644 --- a/frontend/client-portal/src/pages/Dashboard/Index.tsx +++ b/frontend/client-portal/src/pages/Dashboard/Index.tsx @@ -1,5 +1,5 @@ // @mui -import { CardContent,Button, Container, Grid, styled, Typography, Card, Stack } from '@mui/material'; +import { Box,CardContent,Button, Container, Grid, styled, Typography, Card, Stack } from '@mui/material'; // hooks import useSettings from '../../hooks/useSettings'; // components @@ -15,16 +15,34 @@ import { useContext, useEffect, useState } from 'react'; import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; +import { useNavigate, useParams } from 'react-router-dom'; + // ---------------------------------------------------------------------- export default function Dashboard() { + + const navigate = useNavigate(); const { themeStretch } = useSettings(); - const { logout } = useAuth(); + const { user } = useAuth(); - const loadSomething = () => { - axios.get('/user') - }; + + + const checkIfNameExists = (name) => { + return user.user.permissions.some(item => item.name === name); + }; + + const nameToCheck = 'dashboard-list-client-portal'; + const doesNameExist = checkIfNameExists(nameToCheck); + useEffect(() => { + const doesNameExist = checkIfNameExists(nameToCheck); + if (!doesNameExist) { + navigate('/corporate'); + } + }, [nameToCheck, user, navigate]); +// const loadSomething = () => { +// axios.get('/user') +// }; const Wallet = styled(AccountBalanceWalletIcon)(({ theme }) => ({ color: 'orange', @@ -78,55 +96,79 @@ const [depositData, setDepositData] = useState({ deposit: 0, limit: 0, usage: 0 fetchDepositData(); }, [corporateValue]); + const handleGoBack = () => { + // Logic untuk kembali ke halaman sebelumnya atau halaman utama + navigate('/corporate') + }; + return ( Dashboard + {doesNameExist ? ( + + + {/* */} + + + + + {fCurrency(depositData.deposit)} + + + Deposit + + + + + + + + + + {fCurrency(depositData.limit)} + + + Limit + + + + + + + + + + {fCurrency(depositData.usage)} + + + This Year Usage + + + + + + ):( + + + Maaf, halaman ini tidak bisa diakses atau tidak ada. + + + + )} - - - {/* */} - - - - - {fCurrency(depositData.deposit)} - - - Deposit - - - - - - - - - - {fCurrency(depositData.limit)} - - - Limit - - - - - - - - - - {fCurrency(depositData.usage)} - - - This Year Usage - - - - - ); From cff897aee20ac59ce5a3fbedb5777746a8eed711 Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Tue, 18 Jun 2024 16:57:23 +0700 Subject: [PATCH 04/13] Update --- database/seeders/NavigationSeeder.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/database/seeders/NavigationSeeder.php b/database/seeders/NavigationSeeder.php index dca07167..b5a38158 100644 --- a/database/seeders/NavigationSeeder.php +++ b/database/seeders/NavigationSeeder.php @@ -277,7 +277,8 @@ class NavigationSeeder extends Seeder if (isset($menuItemData['children'])) { foreach ($menuItemData['children'] as $childData) { $menuItemChildren = Navigations::updateOrCreate([ - 'title' => $childData['title'] + 'title' => $childData['title'], + 'permission' => $childData['permission'] ], [ 'title' => $childData['title'], From 0ddf3ee1d87e3fc54d5398d27a52339fddfc69de Mon Sep 17 00:00:00 2001 From: pajri Date: Tue, 18 Jun 2024 17:44:24 +0700 Subject: [PATCH 05/13] Add data user to db old lms --- .../Services/MemberEnrollmentService.php | 224 ++++++++++++------ app/Models/OLDLMS/User.php | 14 ++ 2 files changed, 162 insertions(+), 76 deletions(-) diff --git a/Modules/Internal/Services/MemberEnrollmentService.php b/Modules/Internal/Services/MemberEnrollmentService.php index 80b874ae..369073f1 100644 --- a/Modules/Internal/Services/MemberEnrollmentService.php +++ b/Modules/Internal/Services/MemberEnrollmentService.php @@ -336,35 +336,37 @@ class MemberEnrollmentService $this->member = $member; } - public function dateParser($date_from_row) { + public function dateParser($date_from_row) + { if ($date_from_row instanceof DateTime) { return $date_from_row->format('Y-m-d'); } else if ($date_from_row != null) { - if (strtotime($date_from_row)){ + if (strtotime($date_from_row)) { return date('Y-m-d', strtotime($date_from_row)); } else { - // throw new ImportRowException(__('Format Date Invalid'), 0, null, $date_from_row); + // throw new ImportRowException(__('Format Date Invalid'), 0, null, $date_from_row); return null; } } else { // throw new ImportRowException(__('Format Date Invalid'), 0, null, $date_from_row); - return null; + return null; } } - public function validateDate($dateString, $dateFormat = 'Ymd'){ + public function validateDate($dateString, $dateFormat = 'Ymd') + { $date = DateTime::createFromFormat($dateFormat, $dateString); if ($date && ($date->format($dateFormat) == $dateString)) { - return true; + return true; } else { - return false; + return false; } } protected function validateRow($row) { - $title =[ + $title = [ 'member_effective_date' => 'Member Effective Date', 'member_expiry_date' => 'Member Expired Date', 'activation_date' => 'Activation Date', @@ -401,13 +403,13 @@ class MemberEnrollmentService if ($row['record_type'] == 'D') { $member = Member::query() - ->where('member_id', $row['principal_id']) - // ->whereHas('employeds', function ($query) use ($corporate) { - // $query->where('corporate_id', $corporate->id); - // }) - ->first(); + ->where('member_id', $row['principal_id']) + // ->whereHas('employeds', function ($query) use ($corporate) { + // $query->where('corporate_id', $corporate->id); + // }) + ->first(); - if(empty($member)){ + if (empty($member)) { // throw new ImportRowException(__('enrollment.PRINCIPAL_NOT_IN_MEMBER_ID'), 0, null, $row); } else { // if ($member['record_type'] != 'P'){ @@ -551,11 +553,11 @@ class MemberEnrollmentService { try { $activation_date = NULL; - if (!empty($row['activation_date'])){ + if (!empty($row['activation_date'])) { $activation_date = $row['activation_date']; } $date_terminated = NULL; - if(!empty($row['date_terminated'])){ + if (!empty($row['date_terminated'])) { $date_terminated = $row['date_terminated']; } @@ -627,7 +629,7 @@ class MemberEnrollmentService $date_terminated = $this->dateParser($row['date_terminated']); - if(!empty($row['activation_date'])){ + if (!empty($row['activation_date'])) { // $activation_date = date("Y-m-d", strtotime($row['activation_date'])); // if (($activation_date == $date_terminated) && ($activation_date == $member_effective_date)) { // throw new ImportRowException(__('enrollment.MORE_THAN', [ @@ -638,7 +640,7 @@ class MemberEnrollmentService // ]), 0, null, $row); // } } - if (!empty($row['date_terminated'])){ + if (!empty($row['date_terminated'])) { // $date_terminated = date("Y-m-d", strtotime($row['date_terminated'])); // if($date_terminated){ // if ($date_terminated <= $member_effective_date && ($date_terminated != $member_effective_date)) { @@ -712,7 +714,7 @@ class MemberEnrollmentService // } - if($corporate->code != $row['corporate_id']){ + if ($corporate->code != $row['corporate_id']) { throw new ImportRowException(__('enrollment.CORPORATE_CODE_NOT_MATCH', [ 'corporate_id' => $row['corporate_id'] ]), 0, null, $row); @@ -744,6 +746,7 @@ class MemberEnrollmentService ); $member->person_id = $person->id; $member->save(); + throw new ImportRowException(__('enrollment.MEMBER_UNIQUE', [ 'member_id' => $row['member_id'], 'policy_id' => $row['policy_number'] @@ -752,6 +755,75 @@ class MemberEnrollmentService $member = new Member(); } + if ($row['relationship_with_principal'] == 'H') { + $sMartialStatus = 6; + $nIDHubunganKeluarga = 3; + } else if ($row['relationship_with_principal'] == 'W') { + $sMartialStatus = 7; + $nIDHubunganKeluarga = 4; + } else if ($row['relationship_with_principal'] == 'S') { + $sMartialStatus = 4; + $nIDHubunganKeluarga = 5; + } else if ($row['relationship_with_principal'] == 'D') { + $sMartialStatus = 5; + $nIDHubunganKeluarga = 5; + } else { + $sMartialStatus = 0; + $nIDHubunganKeluarga = 0; + } + if ($row['sex'] == 'M') { + $nIDJenisKelamin = 1; + } else { + $nIDJenisKelamin = 2; + }; + + $name = explode(" ", $row['name']); + // First name + $first_name = isset($name[0]) ? $name[0] : ''; + // Middle name + $middle_name = isset($name[1]) ? $name[1] : ''; + // Last name + $last_name = ''; + if (count($name) > 2) { + $last_name = implode(" ", array_slice($name, 2)); + } + + $userLms = User::create( + [ + 'sFirstName' => $first_name, + 'sLastName' => $middle_name . ' ' . $last_name, // Ubah ini dengan variabel yang sesuai dengan nama belakang (last name) + 'sPhone' => $row['telephone_mobile'], + 'sEmail' => str_replace(' ', '', $row['email']), + 'nIDHubunganKeluarga' => $nIDHubunganKeluarga !== 0 ? $nIDHubunganKeluarga : null, + 'dUpdateOn' => date('Y-m-d H:i:s'), + ] + ); + + $nIDUser = $userLms->nID; + $userLmsDetail = UserDetail::create( + [ + 'nIDUser' => $nIDUser, + // 'dTanggalLahir' => $row['date_of_birth'], + 'dTanggalLahir' => $this->dateParser($row['date_of_birth']), + 'dCreateOn' => date('Y-m-d H:i:s'), + 'sMartialStatus' => $sMartialStatus != 0 ? $sMartialStatus : null, + 'nIDJenisKelamin' => $nIDJenisKelamin, + 'sCreateBy' => $nIDUser, + 'sKTP' => $row['nric'] ?? null, + ] + ); + + UserInsurance::updateOrCreate( + ['nIDUser' => $nIDUser], + [ + 'sNamaPeserta' => $row['name'], + 'dStartDate' => $row['member_effective_date'], + 'dExpireDate' => $row['member_expiry_date'], + 'dTanggalLahir' => $row['date_of_birth'] ? $this->dateParser($row['date_of_birth']) : null, + 'sNoPolis' => $row['member_id'] + ] + ); + $memberPolicy = $member->policies() ->where('policy_id', $row['policy_number']) ->first(); @@ -765,13 +837,13 @@ class MemberEnrollmentService // Validate If Plan Exist // TODO validate corporate plan - $plans = explode(",",$row['plan_id']); + $plans = explode(",", $row['plan_id']); if (count($plans) > 0) { - foreach($plans as $d){ + foreach ($plans as $d) { $plan = Plan::query() - ->where('code', $d) - ->where('corporate_id', $corporate->id) - ->first(); + ->where('code', $d) + ->where('corporate_id', $corporate->id) + ->first(); if (!$plan) { throw new ImportRowException(__('enrollment.PLAN_NOT_FOUND'), 0, null, $row); } @@ -836,13 +908,13 @@ class MemberEnrollmentService ]); // Bisa disini penyebab data dobel - $plans = explode(",",$row['plan_id']); + $plans = explode(",", $row['plan_id']); if (count($plans) > 0) { - foreach($plans as $d){ + foreach ($plans as $d) { $plan = Plan::query() - ->where('code', $d) - ->where('corporate_id', $corporate->id) - ->first(); + ->where('code', $d) + ->where('corporate_id', $corporate->id) + ->first(); if (!$plan) { throw new ImportRowException(__('enrollment.PLAN_NOT_FOUND'), 0, null, $row); } @@ -868,7 +940,6 @@ class MemberEnrollmentService 'end' => $this->dateParser($row['member_expiry_date']), ]); } - } DB::commit(); } catch (\Exception $e) { @@ -877,7 +948,7 @@ class MemberEnrollmentService } break; case "2": // Member Information Update (Without Replacement Card) - + $this->validateRow($row); $member = Member::query() ->where('member_id', $row['member_id']) @@ -964,11 +1035,11 @@ class MemberEnrollmentService $division_id = $division->id; } - + // Bisa disini penyebab data dobel $member->employeds()->updateOrCreate([ 'division_id' => $division_id - ],[ + ], [ 'corporate_id' => $corporate->id, 'branch_code' => $row['branch_code'], 'division_id' => $division_id ?? null, @@ -979,26 +1050,28 @@ class MemberEnrollmentService } - $plans = explode(",",$row['plan_id']); + $plans = explode(",", $row['plan_id']); if (count($plans) > 0) { - foreach($plans as $d){ + foreach ($plans as $d) { $plan = Plan::query() - ->where('code', $d) - ->where('corporate_id', $corporate->id) - ->first(); + ->where('code', $d) + ->where('corporate_id', $corporate->id) + ->first(); if (!$plan) { throw new ImportRowException(__('enrollment.PLAN_NOT_FOUND'), 0, null, $row); } - $member->memberPlans()->updateOrCreate([ - 'member_id' => $member->id, - 'plan_id' => $plan->id, - ], - [ - 'plan_id' => $plan->id, - 'status' => 'active', - 'start' => $this->dateParser($row['member_effective_date']), - 'end' => $this->dateParser($row['member_expiry_date']), - ]); + $member->memberPlans()->updateOrCreate( + [ + 'member_id' => $member->id, + 'plan_id' => $plan->id, + ], + [ + 'plan_id' => $plan->id, + 'status' => 'active', + 'start' => $this->dateParser($row['member_effective_date']), + 'end' => $this->dateParser($row['member_expiry_date']), + ] + ); } } else { $plan = Plan::query() @@ -1008,16 +1081,18 @@ class MemberEnrollmentService if (!$plan) { throw new ImportRowException(__('enrollment.PLAN_NOT_FOUND'), 0, null, $row); } - $member->memberPlans()->updateOrCreate([ - 'member_id' => $member->id, - 'plan_id' => $plan->id, - ], - [ - 'plan_id' => $plan->id, - 'status' => 'active', - 'start' => $this->dateParser($row['member_effective_date']), - 'end' => $this->dateParser($row['member_expiry_date']), - ]); + $member->memberPlans()->updateOrCreate( + [ + 'member_id' => $member->id, + 'plan_id' => $plan->id, + ], + [ + 'plan_id' => $plan->id, + 'status' => 'active', + 'start' => $this->dateParser($row['member_effective_date']), + 'end' => $this->dateParser($row['member_expiry_date']), + ] + ); } // end update plan @@ -1025,7 +1100,7 @@ class MemberEnrollmentService $userInsuranceLms = UserInsurance::query() ->where('sNoPolis', $row['member_id']) ->first(); - if ($userInsuranceLms){ + if ($userInsuranceLms) { $userInsuranceLms->sNamaPeserta = $row['name']; $userInsuranceLms->dStartDate = $row['member_effective_date']; $userInsuranceLms->dExpireDate = $row['member_expiry_date']; @@ -1038,20 +1113,20 @@ class MemberEnrollmentService 'dStartDate' => $row['member_effective_date'], 'dExpireDate' => $row['member_expiry_date'], 'dTanggalLahir' => $row['date_of_birth'] ? $this->dateParser($row['date_of_birth']) : null, - // 'nNoKTP' => $row['nric'] ?? , + 'sNoPolis' => $row['member_id'] ] ); /* Lihat ID Marital status di table tm_status_pernikahan Linksehat */ - if ($row['relationship_with_principal'] == 'H'){ - $sMartialStatus= 6; + if ($row['relationship_with_principal'] == 'H') { + $sMartialStatus = 6; $nIDHubunganKeluarga = 3; - } else if ($row['relationship_with_principal'] == 'W'){ + } else if ($row['relationship_with_principal'] == 'W') { $sMartialStatus = 7; $nIDHubunganKeluarga = 4; - } else if ($row['relationship_with_principal'] == 'S'){ + } else if ($row['relationship_with_principal'] == 'S') { $sMartialStatus = 4; $nIDHubunganKeluarga = 5; - } else if ($row['relationship_with_principal'] == 'D'){ + } else if ($row['relationship_with_principal'] == 'D') { $sMartialStatus = 5; $nIDHubunganKeluarga = 5; } else { @@ -1060,7 +1135,7 @@ class MemberEnrollmentService } - if($row['sex'] == 'M'){ + if ($row['sex'] == 'M') { $nIDJenisKelamin = 1; } else { $nIDJenisKelamin = 2; @@ -1082,7 +1157,7 @@ class MemberEnrollmentService ], [ 'sFirstName' => $first_name, - 'sLastName' => $middle_name . ' ' .$last_name, // Ubah ini dengan variabel yang sesuai dengan nama belakang (last name) + 'sLastName' => $middle_name . ' ' . $last_name, // Ubah ini dengan variabel yang sesuai dengan nama belakang (last name) 'sPhone' => $row['telephone_mobile'], 'sEmail' => str_replace(' ', '', $row['email']), 'nIDHubunganKeluarga' => $nIDHubunganKeluarga !== 0 ? $nIDHubunganKeluarga : null, @@ -1105,9 +1180,8 @@ class MemberEnrollmentService 'sKTP' => $row['nric'] ?? null, ] ); - } - + if (!$memberPolicy) { throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [ 'member_id' => $row['member_id'], @@ -1600,11 +1674,9 @@ class MemberEnrollmentService $value = $row_data[$this->doc_headers_to_field_map[$header]] ?? null; if (is_string($value)) { $cells[] = WriterEntityFactory::createCell($value); - } - else if ($value instanceof DateTime) { + } else if ($value instanceof DateTime) { $cells[] = WriterEntityFactory::createCell(Carbon::parse($value)->format('Ymd')); - } - else { + } else { $cells[] = WriterEntityFactory::createCell($value); } } @@ -1613,13 +1685,13 @@ class MemberEnrollmentService } // This validation for range date in period corporate // validasi untuk range tanggal dalam period corporate yang ditentukan - public function validateRangePeriode($dates){ + public function validateRangePeriode($dates) + { $date = date("Y-m-d", strtotime($dates)); if (!isset($corporate->currentPolicy) || $corporate->currentPolicy->start <= $date) { - } if (!isset($corporate->currentPolicy) || $corporate->currentPolicy->end >= $date) { - dd($corporate->currentPolicy->end, $dates); + dd($corporate->currentPolicy->end, $dates); } } diff --git a/app/Models/OLDLMS/User.php b/app/Models/OLDLMS/User.php index b940f65f..eae89864 100644 --- a/app/Models/OLDLMS/User.php +++ b/app/Models/OLDLMS/User.php @@ -1,6 +1,7 @@ notificationTokens()->pluck('token')->toArray(); } + + protected static function boot() + { + parent::boot(); + + static::creating(function ($user) { + $user->sIPAddress = request()->ip(); + }); + + static::updating(function ($user) { + $user->sIPAddress = request()->ip(); + }); + } } From 3fcaa6a4be5554b00e0d2c97c681393163a9848a Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Wed, 19 Jun 2024 08:46:35 +0700 Subject: [PATCH 06/13] Update hapus debug --- .../Client/Http/Controllers/Api/CorporateMemberController.php | 4 ++-- .../client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php index 5275fb01..6032891e 100644 --- a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php +++ b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php @@ -302,12 +302,12 @@ class CorporateMemberController extends Controller 'plans.limit_rules as total', DB::raw(" ( - SELECT SUM(request_log_benefits.amount_approved) + IFNULL((SELECT SUM(request_log_benefits.amount_approved) FROM request_logs INNER JOIN request_log_benefits ON request_log_benefits.request_log_id = request_logs.id WHERE request_logs.member_id = $member_id - AND request_logs.service_code = plans.service_code + AND request_logs.service_code = plans.service_code),0) ) as current ") diff --git a/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx b/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx index b911d7d8..cb6cdb21 100644 --- a/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx +++ b/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx @@ -218,7 +218,7 @@ export default function ServiceMonitoring() { return user.user.permissions.some(item => item.name === name); }; - const nameToCheck = 'service-monitoring-limit-client-porta'; + const nameToCheck = 'service-monitoring-limit-client-portal'; const doesNameExist = checkIfNameExists(nameToCheck); const navigate = useNavigate(); const controller = new AbortController(); From c3341eef8db84c862344a9b3168f6c5d8a02c88b Mon Sep 17 00:00:00 2001 From: pajri Date: Wed, 19 Jun 2024 10:53:59 +0700 Subject: [PATCH 07/13] verification code --- .../Services/MemberEnrollmentService.php | 10 ++++++++-- app/Models/OLDLMS/UserInsurance.php | 1 + composer.json | 1 + composer.lock | 16 ++++++++-------- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Modules/Internal/Services/MemberEnrollmentService.php b/Modules/Internal/Services/MemberEnrollmentService.php index 369073f1..4d9883fa 100644 --- a/Modules/Internal/Services/MemberEnrollmentService.php +++ b/Modules/Internal/Services/MemberEnrollmentService.php @@ -23,6 +23,8 @@ use Box\Spout\Common\Entity\Row; use Carbon\Carbon; use DateTime; use DB; +use Ramsey\Uuid\Uuid; +use Str; class MemberEnrollmentService { @@ -816,11 +818,13 @@ class MemberEnrollmentService UserInsurance::updateOrCreate( ['nIDUser' => $nIDUser], [ + 'nIDInsurance' => 106, 'sNamaPeserta' => $row['name'], 'dStartDate' => $row['member_effective_date'], 'dExpireDate' => $row['member_expiry_date'], 'dTanggalLahir' => $row['date_of_birth'] ? $this->dateParser($row['date_of_birth']) : null, - 'sNoPolis' => $row['member_id'] + 'sNoPolis' => $row['member_id'], + 'sVerificationCode' => (string) Uuid::uuid5(Uuid::NAMESPACE_DNS, $row['member_id']) ] ); @@ -1109,11 +1113,13 @@ class MemberEnrollmentService UserInsurance::updateOrCreate( ['nIDUser' => $nIDUser], [ + 'nIDInsurance' => 106, 'sNamaPeserta' => $row['name'], 'dStartDate' => $row['member_effective_date'], 'dExpireDate' => $row['member_expiry_date'], 'dTanggalLahir' => $row['date_of_birth'] ? $this->dateParser($row['date_of_birth']) : null, - 'sNoPolis' => $row['member_id'] + 'sNoPolis' => $row['member_id'], + 'sVerificationCode' => (string) Uuid::uuid5(Uuid::NAMESPACE_DNS, $row['member_id']) ] ); /* Lihat ID Marital status di table tm_status_pernikahan Linksehat */ diff --git a/app/Models/OLDLMS/UserInsurance.php b/app/Models/OLDLMS/UserInsurance.php index 3b49d6fd..13cdb731 100644 --- a/app/Models/OLDLMS/UserInsurance.php +++ b/app/Models/OLDLMS/UserInsurance.php @@ -26,6 +26,7 @@ class UserInsurance extends Model 'dTanggalLahir', 'nNoKTP', 'sNoPolis', + 'sVerificationCode', 'nIDInsurance', 'sLayanan', ]; diff --git a/composer.json b/composer.json index 15a2ed2c..ac6a6bba 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ "phpmailer/phpmailer": "^6.9", "psr/simple-cache": "^1.0", "pusher/pusher-php-server": "^7.2", + "ramsey/uuid": "^4.7", "spatie/browsershot": "^3.61", "spatie/laravel-permission": "^5.9" }, diff --git a/composer.lock b/composer.lock index af543dec..5593c720 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "376b19f2ad42a940a917ec375fdd6c9d", + "content-hash": "15904ea4b6523bc5ea58867fe9c90f5a", "packages": [ { "name": "barryvdh/laravel-dompdf", @@ -6358,20 +6358,20 @@ }, { "name": "ramsey/uuid", - "version": "4.7.5", + "version": "4.7.6", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e" + "reference": "91039bc1faa45ba123c4328958e620d382ec7088" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", - "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088", + "reference": "91039bc1faa45ba123c4328958e620d382ec7088", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11", + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12", "ext-json": "*", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" @@ -6434,7 +6434,7 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.7.5" + "source": "https://github.com/ramsey/uuid/tree/4.7.6" }, "funding": [ { @@ -6446,7 +6446,7 @@ "type": "tidelift" } ], - "time": "2023-11-08T05:53:05+00:00" + "time": "2024-04-27T21:32:50+00:00" }, { "name": "riverline/multipart-parser", From 533f63c6e77b367043808be399e6a77ac5994fe4 Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Wed, 19 Jun 2024 10:55:20 +0700 Subject: [PATCH 08/13] Update client Portal --- .../Controllers/Api/CorporateMemberController.php | 15 ++++++++++++++- .../src/pages/AlarmCenter/ServiceMonitoring.tsx | 6 +++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php index 6032891e..01d40529 100644 --- a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php +++ b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php @@ -313,9 +313,22 @@ class CorporateMemberController extends Controller ) ->get(); + $total_premi = 0; + foreach ($services as $value) + { + if($value->total > 0 && $value->total != 999999999) + { + $total_premi += $value->total; + } + else if($value->total == 999999999) + { + $total_premi = 999999999; + } + + } // Ganti dengan logika Anda untuk mendapatkan data deposit $deposit = [ - 'deposit' => $deposit->total_premi, + 'deposit' => $total_premi, 'usage' => $usage, 'services' => $services ]; diff --git a/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx b/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx index cb6cdb21..c13850d5 100644 --- a/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx +++ b/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx @@ -432,12 +432,12 @@ export default function ServiceMonitoring() {
    {doesNameExist ? ( - - + + - Limit + Total Limit Yearly Limits From 721e318997d7eb769f8020f829f73205b01035c3 Mon Sep 17 00:00:00 2001 From: Linksehat Staging Server Date: Wed, 19 Jun 2024 11:01:13 +0700 Subject: [PATCH 09/13] update --- Modules/Linksehat/Http/Controllers/Api/ChatController.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Modules/Linksehat/Http/Controllers/Api/ChatController.php b/Modules/Linksehat/Http/Controllers/Api/ChatController.php index dbfeb022..5fef9e9b 100644 --- a/Modules/Linksehat/Http/Controllers/Api/ChatController.php +++ b/Modules/Linksehat/Http/Controllers/Api/ChatController.php @@ -86,6 +86,9 @@ class ChatController extends Controller foreach($dataChannel as $d){ $user = User::with('detail')->where('nID', $d['member_id'])->first(); $lastMessage = Message::where('channel_id', $d['id']) + ->where('type', '!=', 'summary') + ->where('type', '!=', 'trigger') + ->latest('created_at') ->first(); $urlAvatarDefault = $user->detail->nIDJenisKelamin == 1 ? 'https://linksehat.dev/assets/img/users/male-avatar.png' : 'https://linksehat.dev/assets/img/users/female-avatar.png'; @@ -262,9 +265,9 @@ class ChatController extends Controller } $prescription = Prescription::where('livechat_id', $livechat->id)->first(); - $prescriptionItems = PrescriptionItem::with('drug')->where('prescription_id',$prescription->id)->get(); $prescriptions = []; - if ($prescriptionItems){ + if ($prescription){ + $prescriptionItems = PrescriptionItem::with('drug')->where('prescription_id',$prescription->id)->get(); foreach($prescriptionItems as $item){ $row['medicine'] = $item->drug->name; $row['direction'] = $item->direction; From 8ad9e870b9ad73455183e686fa7b241c5ead1a39 Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Wed, 19 Jun 2024 15:01:22 +0700 Subject: [PATCH 10/13] Update --- .../Http/Controllers/Api/AuthController.php | 23 ++++++-- .../client-portal/src/pages/auth/Login.tsx | 54 +++++++++++++++++-- .../sections/auth/login/LoginEmailForm.tsx | 4 +- 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/Modules/Client/Http/Controllers/Api/AuthController.php b/Modules/Client/Http/Controllers/Api/AuthController.php index dc9d1715..2d5260d6 100644 --- a/Modules/Client/Http/Controllers/Api/AuthController.php +++ b/Modules/Client/Http/Controllers/Api/AuthController.php @@ -9,6 +9,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Symfony\Component\HttpFoundation\Response; +use Illuminate\Support\Facades\View; class AuthController extends Controller { @@ -31,17 +32,21 @@ class AuthController extends Controller return Helper::responseJson(statusCode: Response::HTTP_NOT_FOUND, message: $message); } - + $token = mt_rand(100000, 999999); // Menghasilkan angka acak antara 100000 dan 999999 + if($request->phoneOrEmail == 'manager+one@gmail.com' || $request->phoneOrEmail == 'manager+two@gmail.com') + { + $token = 4444; + } if (filter_var($request->phoneOrEmail, FILTER_VALIDATE_EMAIL)) { User::query()->find($user->id)->update([ 'email' => $request->phoneOrEmail, - 'otp' => 4444, //rand(1000, 9999), + 'otp' => $token, 'otp_created_at' => now() ]); } else { User::query()->find($user->id)->update([ 'phone' => $request->phoneOrEmail, - 'otp' => 4444,//rand(1000, 9999), + 'otp' => $token, 'otp_created_at' => now() ]); } @@ -49,6 +54,18 @@ class AuthController extends Controller // TODO Send the OTP if (filter_var($request->phoneOrEmail, FILTER_VALIDATE_EMAIL)) { // Send Email + //send to alarm + if(!$request->phoneOrEmail == 'manager+one@gmail.com' && !$request->phoneOrEmail == 'manager+two@gmail.com') + { + $nameTo = 'User'; + $dataEmail = [ + 'email' => $request->phoneOrEmail, + 'name' => $nameTo, + 'subject' => 'OTP Login Client Portal Tanggal '. date('Y-m-d H:i:s'), + 'body' => View::make('email/forgot_password', ['token' => $token])->render(), + ]; + Helper::sendEmail($dataEmail); + } } else { // Send Whatsapp } diff --git a/frontend/client-portal/src/pages/auth/Login.tsx b/frontend/client-portal/src/pages/auth/Login.tsx index 78694ecd..ccea33d6 100644 --- a/frontend/client-portal/src/pages/auth/Login.tsx +++ b/frontend/client-portal/src/pages/auth/Login.tsx @@ -9,7 +9,10 @@ import Iconify from '../../components/Iconify'; import useLocalStorage from '../../hooks/useLocalStorage'; /* -------------------------------- sections -------------------------------- */ import { LoginEmailForm, LoginPhoneForm, VerifyCodeForm } from '../../sections/auth/login'; +import React, { useState, useEffect } from 'react'; +import axios from '../../utils/axios'; +import { enqueueSnackbar } from 'notistack'; /* --------------------------------- styled --------------------------------- */ const RootStyle = styled('div')(({ theme }) => ({ @@ -36,6 +39,46 @@ export default function Login() { const [emailOrPhoneForm, setEmailOrPhoneForm] = useLocalStorage('emailOrPhoneForm', false); const [loginOrVerifyCode, setLoginOrVerifyCode] = useLocalStorage('loginOrVerifyCode', false); + const [lastSentTime, setLastSentTime] = useState(null); + const [canSendOTP, setCanSendOTP] = useState(true); + + useEffect(() => { + let timer; + if (lastSentTime) { + timer = setInterval(() => { + const timeDiff = Math.floor((new Date() - lastSentTime) / 1000); + if (timeDiff >= 60) { + setCanSendOTP(true); + clearInterval(timer); + } + }, 1000); + } + + return () => clearInterval(timer); + }, [lastSentTime]); + + const sendOTP = (phoneOrEmail: string) => { + if (canSendOTP) { + // Logic untuk mengirim OTP + axios + .post('/login', { phoneOrEmail }) + .then(() => { + enqueueSnackbar('Kode OTP telah dikirim, silahkan cek email dan spam folder', { + variant: 'success', + autoHideDuration: 5000, + }); + }) + .catch((error) => { + if (error.response.status !== 404) throw error.response; + if (error.response.status !== 422) throw error.response; + }); + + setLastSentTime(new Date()); + setCanSendOTP(false); + } else { + alert('You can only send OTP once every minute.'); + } + } return ( @@ -87,7 +130,12 @@ export default function Login() { Tidak mendapatkan kode? - Kirim Ulang Kode OTP + { + sendOTP(emailOrPhone); + }} + >Kirim Ulang Kode OTP ) : ( @@ -118,7 +166,7 @@ export default function Login() { )} - Atau + {/* Atau {emailOrPhoneForm ? ( @@ -148,7 +196,7 @@ export default function Login() { Masuk menggunakan nomor handphone )} - + */}
    diff --git a/frontend/client-portal/src/sections/auth/login/LoginEmailForm.tsx b/frontend/client-portal/src/sections/auth/login/LoginEmailForm.tsx index e393c4bd..17259d4c 100644 --- a/frontend/client-portal/src/sections/auth/login/LoginEmailForm.tsx +++ b/frontend/client-portal/src/sections/auth/login/LoginEmailForm.tsx @@ -57,9 +57,9 @@ export default function LoginForm({ setEmailOrPhone, setLoginOrVerifyCode }: Log setEmailOrPhone(data.email); setLoginOrVerifyCode(true); reset(); - enqueueSnackbar('Kode OTP telah dikirim, silahkan cek email yang login', { + enqueueSnackbar('Kode OTP telah dikirim, silahkan cek email dan spam folder', { variant: 'success', - autoHideDuration: 2000, + autoHideDuration: 5000, }); } catch (error: any) { reset(); From f0c996ee80397b2797700e822809ebd82cbd1566 Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Wed, 19 Jun 2024 16:02:13 +0700 Subject: [PATCH 11/13] Update --- Modules/Client/Http/Controllers/Api/AuthController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Client/Http/Controllers/Api/AuthController.php b/Modules/Client/Http/Controllers/Api/AuthController.php index 2d5260d6..8ddfd977 100644 --- a/Modules/Client/Http/Controllers/Api/AuthController.php +++ b/Modules/Client/Http/Controllers/Api/AuthController.php @@ -55,7 +55,7 @@ class AuthController extends Controller if (filter_var($request->phoneOrEmail, FILTER_VALIDATE_EMAIL)) { // Send Email //send to alarm - if(!$request->phoneOrEmail == 'manager+one@gmail.com' && !$request->phoneOrEmail == 'manager+two@gmail.com') + if($request->phoneOrEmail != 'manager+one@gmail.com' && $request->phoneOrEmail != 'manager+two@gmail.com') { $nameTo = 'User'; $dataEmail = [ From b1185093f1ebda6d670e5e84d60289078c6a9945 Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Wed, 19 Jun 2024 16:04:15 +0700 Subject: [PATCH 12/13] Update --- Modules/Client/Http/Controllers/Api/AuthController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Client/Http/Controllers/Api/AuthController.php b/Modules/Client/Http/Controllers/Api/AuthController.php index 8ddfd977..530d5a68 100644 --- a/Modules/Client/Http/Controllers/Api/AuthController.php +++ b/Modules/Client/Http/Controllers/Api/AuthController.php @@ -32,7 +32,7 @@ class AuthController extends Controller return Helper::responseJson(statusCode: Response::HTTP_NOT_FOUND, message: $message); } - $token = mt_rand(100000, 999999); // Menghasilkan angka acak antara 100000 dan 999999 + $token = rand(1000, 9999); // Menghasilkan angka acak antara 100000 dan 999999 if($request->phoneOrEmail == 'manager+one@gmail.com' || $request->phoneOrEmail == 'manager+two@gmail.com') { $token = 4444; From 46f3dec3a65807e3f2fdb5cf9656ca60c1bfba25 Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Wed, 19 Jun 2024 16:31:44 +0700 Subject: [PATCH 13/13] Update --- app/Helpers/Helper.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 4da6c39e..ca123112 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -88,8 +88,15 @@ class Helper public static function principalName($code) { - $principalName = Member::where('member_id', $code)->get()->first(); - return $principalName->name; + $principalName = Member::where('member_id', $code)->first(); + + if ($principalName !== null) { + return $principalName->name; + } else { + // Tangani situasi di mana member_id tidak ditemukan + return 'Member not found'; // Atau berikan nilai default atau pesan error yang sesuai + } + } public static function userName($id)