455 changed files with 263 additions and 247632 deletions
@ -0,0 +1,130 @@
|
||||
DROP MATERIALIZED VIEW GENAPP.KPDL_MV_PETUGAS_REKAM; |
||||
|
||||
CREATE MATERIALIZED VIEW GENAPP.KPDL_MV_PETUGAS_REKAM |
||||
(KODE_SEKSI_PEREKAM,KODE_PEG_PEREKAM,ID_KPDL_SUBJEK,KPPADM_PEREKAM,NIP_PEREKAM, |
||||
CREATION_DATE,ORG_APPROVAL_KASI,NIP_APPROVAL_KASI,TGL_APPROVAL_KASI,STS_APPROVAL_KASI, |
||||
TGL_APPROVAL_PKD,STS_APPROVAL_PKD) |
||||
TABLESPACE TS_KPDL |
||||
PCTFREE 10 |
||||
INITRANS 2 |
||||
MAXTRANS 255 |
||||
STORAGE ( |
||||
INITIAL 64K |
||||
NEXT 1M |
||||
MINEXTENTS 1 |
||||
MAXEXTENTS UNLIMITED |
||||
PCTINCREASE 0 |
||||
BUFFER_POOL DEFAULT |
||||
) |
||||
NOCACHE |
||||
NOLOGGING |
||||
NOCOMPRESS |
||||
PARALLEL ( DEGREE DEFAULT INSTANCES DEFAULT ) |
||||
BUILD IMMEDIATE |
||||
REFRESH FORCE ON DEMAND |
||||
WITH PRIMARY KEY |
||||
AS |
||||
SELECT |
||||
COALESCE(a.KPP_ADM_PEREKAM, '') || '-' || COALESCE (ORG_APPROVAL_KASI,'') KODE_SEKSI_PEREKAM, |
||||
COALESCE(a.KPP_ADM_PEREKAM, '') || '-' || COALESCE (ORG_APPROVAL_KASI, |
||||
'') || '-' || COALESCE (a.CREATED_BY, |
||||
'') KODE_PEG_PEREKAM, |
||||
a.ID_KPDL_SUBJEK, |
||||
a.KPP_ADM_PEREKAM KPPADM_PEREKAM, |
||||
a.CREATED_BY NIP_PEREKAM, |
||||
a.CREATION_DATE, |
||||
b.ORG_APPROVAL_KASI, |
||||
b.NIP_APPROVAL_KASI, |
||||
b.TGL_APPROVAL_KASI, |
||||
b.STS_APPROVAL_KASI, |
||||
b.TGL_APPROVAL_PKD, |
||||
b.STS_APPROVAL_PKD |
||||
FROM |
||||
KPDL_SUBJEK a |
||||
LEFT JOIN KPDL_TRX b ON |
||||
(a.ID_KPDL_SUBJEK = b.ID_KPDL_SUBJEK) |
||||
WHERE |
||||
a.FG_SUMBER = 'MATOA'; |
||||
|
||||
|
||||
COMMENT ON MATERIALIZED VIEW GENAPP.KPDL_MV_PETUGAS_REKAM IS 'snapshot table for snapshot GENAPP.KPDL_MV_PETUGAS_REKAM'; |
||||
|
||||
CREATE INDEX GENAPP.KPDL_MV_PETUGAS_REKAM_CREATION_DATE_IDX ON GENAPP.KPDL_MV_PETUGAS_REKAM |
||||
(CREATION_DATE) |
||||
LOGGING |
||||
TABLESPACE USERS |
||||
PCTFREE 10 |
||||
INITRANS 2 |
||||
MAXTRANS 255 |
||||
STORAGE ( |
||||
INITIAL 64K |
||||
NEXT 1M |
||||
MINEXTENTS 1 |
||||
MAXEXTENTS UNLIMITED |
||||
PCTINCREASE 0 |
||||
BUFFER_POOL DEFAULT |
||||
); |
||||
|
||||
CREATE INDEX GENAPP.KPDL_MV_PETUGAS_REKAM_ID_KPDL_SUBJEK_IDX ON GENAPP.KPDL_MV_PETUGAS_REKAM |
||||
(ID_KPDL_SUBJEK) |
||||
LOGGING |
||||
TABLESPACE USERS |
||||
PCTFREE 10 |
||||
INITRANS 2 |
||||
MAXTRANS 255 |
||||
STORAGE ( |
||||
INITIAL 64K |
||||
NEXT 1M |
||||
MINEXTENTS 1 |
||||
MAXEXTENTS UNLIMITED |
||||
PCTINCREASE 0 |
||||
BUFFER_POOL DEFAULT |
||||
); |
||||
|
||||
CREATE INDEX GENAPP.KPDL_MV_PETUGAS_REKAM_KODE_PEG_PEREKAM_IDX ON GENAPP.KPDL_MV_PETUGAS_REKAM |
||||
(KODE_PEG_PEREKAM) |
||||
LOGGING |
||||
TABLESPACE USERS |
||||
PCTFREE 10 |
||||
INITRANS 2 |
||||
MAXTRANS 255 |
||||
STORAGE ( |
||||
INITIAL 64K |
||||
NEXT 1M |
||||
MINEXTENTS 1 |
||||
MAXEXTENTS UNLIMITED |
||||
PCTINCREASE 0 |
||||
BUFFER_POOL DEFAULT |
||||
); |
||||
|
||||
CREATE INDEX GENAPP.KPDL_MV_PETUGAS_REKAM_KODE_SEKSI_PEREKAM_IDX ON GENAPP.KPDL_MV_PETUGAS_REKAM |
||||
(KODE_SEKSI_PEREKAM) |
||||
LOGGING |
||||
TABLESPACE USERS |
||||
PCTFREE 10 |
||||
INITRANS 2 |
||||
MAXTRANS 255 |
||||
STORAGE ( |
||||
INITIAL 64K |
||||
NEXT 1M |
||||
MINEXTENTS 1 |
||||
MAXEXTENTS UNLIMITED |
||||
PCTINCREASE 0 |
||||
BUFFER_POOL DEFAULT |
||||
); |
||||
|
||||
CREATE INDEX GENAPP.KPDL_MV_PETUGAS_REKAM_NIP_PEREKAM_IDX ON GENAPP.KPDL_MV_PETUGAS_REKAM |
||||
(NIP_PEREKAM) |
||||
LOGGING |
||||
TABLESPACE USERS |
||||
PCTFREE 10 |
||||
INITRANS 2 |
||||
MAXTRANS 255 |
||||
STORAGE ( |
||||
INITIAL 64K |
||||
NEXT 1M |
||||
MINEXTENTS 1 |
||||
MAXEXTENTS UNLIMITED |
||||
PCTINCREASE 0 |
||||
BUFFER_POOL DEFAULT |
||||
); |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,35 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */ |
||||
// ** React Imports
|
||||
import React from 'react' |
||||
const Ind = require('flatpickr/dist/l10n/id.js').default.id // ** Reactstrap Imports
|
||||
import { Label } from 'reactstrap' |
||||
|
||||
// ** Third Party Components
|
||||
import Flatpickr from 'react-flatpickr' |
||||
// ** Styles
|
||||
import '../scss/react/libs/flatpickr/flatpickr.scss' |
||||
const Tanggal = ({ startOrEnd, value, setValue }) => { |
||||
// ** State
|
||||
// const [picker, setPicker] = useState(new Date())
|
||||
return ( |
||||
<> |
||||
<Label className="form-label" for="hf-picker"> |
||||
{startOrEnd} |
||||
</Label> |
||||
<Flatpickr |
||||
value={value} |
||||
id="hf-picker" |
||||
className="form-control tanggal" |
||||
onChange={(date) => setValue(date[0].toISOString())} |
||||
options={{ |
||||
locale: Ind, |
||||
altInput: true, |
||||
altFormat: 'd M Y', |
||||
dateFormat: 'Y-m-d' |
||||
}} |
||||
/> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default Tanggal |
@ -1 +0,0 @@
|
||||
export default "/engineN/public/kpdl/layers.png"; |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 696 B |
@ -1 +0,0 @@
|
||||
export default "/engineN/public/kpdl/layers-2x.png"; |
Before Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
export default "/engineN/public/kpdl/marker-icon.png"; |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,126 +0,0 @@
|
||||
/*! |
||||
Copyright (c) 2018 Jed Watson. |
||||
Licensed under the MIT License (MIT), see |
||||
http://jedwatson.github.io/classnames |
||||
*/ |
||||
|
||||
/*! |
||||
* jQuery JavaScript Library v3.7.1 |
||||
* https://jquery.com/ |
||||
* |
||||
* Copyright OpenJS Foundation and other contributors |
||||
* Released under the MIT license |
||||
* https://jquery.org/license |
||||
* |
||||
* Date: 2023-08-28T13:37Z |
||||
*/ |
||||
|
||||
/** |
||||
* @license @tabler/icons-react v3.16.0 - MIT |
||||
* |
||||
* This source code is licensed under the MIT license. |
||||
* See the LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react-dom.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react-jsx-runtime.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* scheduler.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* use-sync-external-store-with-selector.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* match-sorter-utils |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** |
||||
* react-virtual |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** |
||||
* table-core |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** |
||||
* virtual-core |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** @license React v16.13.1 |
||||
* react-is.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,126 +0,0 @@
|
||||
/*! |
||||
Copyright (c) 2018 Jed Watson. |
||||
Licensed under the MIT License (MIT), see |
||||
http://jedwatson.github.io/classnames |
||||
*/ |
||||
|
||||
/*! |
||||
* jQuery JavaScript Library v3.7.1 |
||||
* https://jquery.com/ |
||||
* |
||||
* Copyright OpenJS Foundation and other contributors |
||||
* Released under the MIT license |
||||
* https://jquery.org/license |
||||
* |
||||
* Date: 2023-08-28T13:37Z |
||||
*/ |
||||
|
||||
/** |
||||
* @license @tabler/icons-react v3.16.0 - MIT |
||||
* |
||||
* This source code is licensed under the MIT license. |
||||
* See the LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react-dom.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react-jsx-runtime.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* scheduler.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* use-sync-external-store-with-selector.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* match-sorter-utils |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** |
||||
* react-virtual |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** |
||||
* table-core |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** |
||||
* virtual-core |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** @license React v16.13.1 |
||||
* react-is.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,43 +0,0 @@
|
||||
/* @preserve |
||||
* Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com |
||||
* (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade |
||||
*/ |
||||
|
||||
/*! |
||||
Copyright (c) 2016 Dominik Moritz |
||||
|
||||
This file is part of the leaflet locate control. It is licensed under the MIT license. |
||||
You can find the project at: https://github.com/domoritz/leaflet-locatecontrol |
||||
*/ |
||||
|
||||
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */ |
||||
|
||||
/** |
||||
* @license React |
||||
* react-dom.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* scheduler.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
@ -1,35 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */ |
||||
// ** React Imports
|
||||
import React from 'react' |
||||
const Ind = require('flatpickr/dist/l10n/id.js').default.id // ** Reactstrap Imports
|
||||
import { Label } from 'reactstrap' |
||||
|
||||
// ** Third Party Components
|
||||
import Flatpickr from 'react-flatpickr' |
||||
// ** Styles
|
||||
import '../scss/react/libs/flatpickr/flatpickr.scss' |
||||
const Tanggal = ({ startOrEnd, value, setValue }) => { |
||||
// ** State
|
||||
// const [picker, setPicker] = useState(new Date())
|
||||
return ( |
||||
<> |
||||
<Label className="form-label" for="hf-picker"> |
||||
{startOrEnd} |
||||
</Label> |
||||
<Flatpickr |
||||
value={value} |
||||
id="hf-picker" |
||||
className="form-control tanggal" |
||||
onChange={(date) => setValue(date[0].toISOString())} |
||||
options={{ |
||||
locale: Ind, |
||||
altInput: true, |
||||
altFormat: 'd M Y', |
||||
dateFormat: 'Y-m-d' |
||||
}} |
||||
/> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default Tanggal |
@ -1 +0,0 @@
|
||||
export default "/engineN/public/kpdl/layers.png"; |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 696 B |
@ -1 +0,0 @@
|
||||
export default "/engineN/public/kpdl/layers-2x.png"; |
Before Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
export default "/engineN/public/kpdl/marker-icon.png"; |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,126 +0,0 @@
|
||||
/*! |
||||
Copyright (c) 2018 Jed Watson. |
||||
Licensed under the MIT License (MIT), see |
||||
http://jedwatson.github.io/classnames |
||||
*/ |
||||
|
||||
/*! |
||||
* jQuery JavaScript Library v3.7.1 |
||||
* https://jquery.com/ |
||||
* |
||||
* Copyright OpenJS Foundation and other contributors |
||||
* Released under the MIT license |
||||
* https://jquery.org/license |
||||
* |
||||
* Date: 2023-08-28T13:37Z |
||||
*/ |
||||
|
||||
/** |
||||
* @license @tabler/icons-react v3.16.0 - MIT |
||||
* |
||||
* This source code is licensed under the MIT license. |
||||
* See the LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react-dom.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react-jsx-runtime.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* scheduler.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* use-sync-external-store-with-selector.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* match-sorter-utils |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** |
||||
* react-virtual |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** |
||||
* table-core |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** |
||||
* virtual-core |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** @license React v16.13.1 |
||||
* react-is.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,126 +0,0 @@
|
||||
/*! |
||||
Copyright (c) 2018 Jed Watson. |
||||
Licensed under the MIT License (MIT), see |
||||
http://jedwatson.github.io/classnames |
||||
*/ |
||||
|
||||
/*! |
||||
* jQuery JavaScript Library v3.7.1 |
||||
* https://jquery.com/ |
||||
* |
||||
* Copyright OpenJS Foundation and other contributors |
||||
* Released under the MIT license |
||||
* https://jquery.org/license |
||||
* |
||||
* Date: 2023-08-28T13:37Z |
||||
*/ |
||||
|
||||
/** |
||||
* @license @tabler/icons-react v3.16.0 - MIT |
||||
* |
||||
* This source code is licensed under the MIT license. |
||||
* See the LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react-dom.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react-jsx-runtime.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* scheduler.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* use-sync-external-store-with-selector.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* match-sorter-utils |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** |
||||
* react-virtual |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** |
||||
* table-core |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** |
||||
* virtual-core |
||||
* |
||||
* Copyright (c) TanStack |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE.md file in the root directory of this source tree. |
||||
* |
||||
* @license MIT |
||||
*/ |
||||
|
||||
/** @license React v16.13.1 |
||||
* react-is.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,43 +0,0 @@
|
||||
/* @preserve |
||||
* Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com |
||||
* (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade |
||||
*/ |
||||
|
||||
/*! |
||||
Copyright (c) 2016 Dominik Moritz |
||||
|
||||
This file is part of the leaflet locate control. It is licensed under the MIT license. |
||||
You can find the project at: https://github.com/domoritz/leaflet-locatecontrol |
||||
*/ |
||||
|
||||
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */ |
||||
|
||||
/** |
||||
* @license React |
||||
* react-dom.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* react.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
||||
|
||||
/** |
||||
* @license React |
||||
* scheduler.production.min.js |
||||
* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
* |
||||
* This source code is licensed under the MIT license found in the |
||||
* LICENSE file in the root directory of this source tree. |
||||
*/ |
@ -1,49 +0,0 @@
|
||||
import React, { useRef, useState } from 'react' |
||||
import { Card, CardBody, CardHeader, CardTitle } from 'reactstrap' |
||||
import { Stepper } from 'primereact/stepper' |
||||
import { StepperPanel } from 'primereact/stepperpanel' |
||||
import PenugasanKpdl from './componentPenugasanAktifitas/PenugasanKpdl.js' |
||||
const TabPenugasan = ({ dataSend }) => { |
||||
const stepperRef = useRef(null) |
||||
return ( |
||||
<> |
||||
<Card> |
||||
<CardHeader className="d-flex justify-content-center p-2"> |
||||
<CardTitle tag={'h1'} className="font-weight-bold"> |
||||
Statistik Penugasan Matoa Tahun Berjalan |
||||
</CardTitle> |
||||
</CardHeader> |
||||
|
||||
<CardBody className="mb-0"> |
||||
<div className="card flex justify-content-center"> |
||||
<Stepper ref={stepperRef} style={{ flexBasis: '30rem' }}> |
||||
<StepperPanel header="Identifikasi Lapangan (KPDL/MATOA)"> |
||||
<div className="flex flex-column h-12rem"> |
||||
<div className="font-medium"> |
||||
<PenugasanKpdl dataSend={dataSend} /> |
||||
</div> |
||||
</div> |
||||
</StepperPanel> |
||||
{/* <StepperPanel header="Aktifitas pasca identifikasi"> |
||||
<div className="flex flex-column h-12rem"> |
||||
<div className="border-2 border-dashed surface-border border-round surface-ground flex-auto flex justify-content-center align-items-center font-medium"> |
||||
OTW |
||||
</div> |
||||
</div> |
||||
</StepperPanel> |
||||
<StepperPanel header="Hasil pasca aktifitas"> |
||||
<div className="flex flex-column h-12rem"> |
||||
<div className="border-2 border-dashed surface-border border-round surface-ground flex-auto flex justify-content-center align-items-center font-medium"> |
||||
OTW |
||||
</div> |
||||
</div> |
||||
</StepperPanel> */} |
||||
</Stepper> |
||||
</div> |
||||
</CardBody> |
||||
</Card> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default TabPenugasan |
@ -1,63 +0,0 @@
|
||||
import React, { useState } from "react" |
||||
import { TabView, TabPanel } from "primereact/tabview" |
||||
// import Identifikasi from "./componentProgresifitas/Identifikasi"
|
||||
import Pembayaran from "./componentProgresifitas/Pembayaran" |
||||
import Identifikasi from "./componentProgresifitas/Identifikasi" |
||||
import PayComp from "./componentProgresifitas/PayComp" |
||||
import Sof from "./componentProgresifitas/Sof" |
||||
import JenisStatusWp from "./componentProgresifitas/JenisStatusWp" |
||||
import Pengampu from "./componentProgresifitas/Pengampu" |
||||
import SPTTahunan from "./componentProgresifitas/SPTTahunan" |
||||
import KLU from "./componentProgresifitas/KLU" |
||||
import ZonaPengawasan from "./componentProgresifitas/ZonaPengawasan" |
||||
import { useDispatch, useSelector } from "react-redux" |
||||
import { isObjEmpty } from "./util" |
||||
|
||||
export default function TabProgresifitas({ dataSend }) { |
||||
const dispatch = useDispatch() |
||||
const storeKpdl = useSelector((state) => state.kpdl) |
||||
|
||||
return ( |
||||
<div className="card"> |
||||
<TabView scrollable> |
||||
<TabPanel id="tab_1" header="Identifikasi"> |
||||
<Identifikasi dataSend={dataSend} /> |
||||
</TabPanel> |
||||
|
||||
<TabPanel id="tab_2" header="Pembayaran"> |
||||
<Pembayaran dataSend={dataSend} /> |
||||
</TabPanel> |
||||
|
||||
<TabPanel id="tab_3" header="Payment Compliance"> |
||||
<PayComp dataSend={dataSend} /> |
||||
</TabPanel> |
||||
|
||||
<TabPanel id="tab_4" header="Strength Of Figure"> |
||||
<div> |
||||
<Sof dataSend={dataSend} /> |
||||
</div> |
||||
</TabPanel> |
||||
<TabPanel id="tab_7" header="SPT Tahunan"> |
||||
<SPTTahunan dataSend={dataSend} /> |
||||
</TabPanel> |
||||
|
||||
<TabPanel id="tab_5" header="Jenis/Status WP"> |
||||
<JenisStatusWp dataSend={dataSend} /> |
||||
</TabPanel> |
||||
{storeKpdl && !isObjEmpty(storeKpdl) && storeKpdl.selectedOpsi && storeKpdl.selectedOpsi?.name !== "pengampu" ? ( |
||||
<TabPanel id="tab_5" header="Pengampu"> |
||||
<Pengampu dataSend={dataSend} /> |
||||
</TabPanel> |
||||
) : null} |
||||
{storeKpdl && !isObjEmpty(storeKpdl) && storeKpdl.selectedOpsi && storeKpdl.selectedOpsi?.name !== "zona" ? ( |
||||
<TabPanel id="tab_6" header="Zona Pengawasan"> |
||||
<ZonaPengawasan dataSend={dataSend} /> |
||||
</TabPanel> |
||||
) : null} |
||||
<TabPanel id="tab_8" header="KLU (Golongan Pokok)"> |
||||
<KLU dataSend={dataSend} /> |
||||
</TabPanel> |
||||
</TabView> |
||||
</div> |
||||
) |
||||
} |
@ -1,185 +0,0 @@
|
||||
import React, { useEffect, useRef, useState } from 'react' |
||||
import { MultiSelect } from 'react-multi-select-component' |
||||
import { Col, Label, Row } from 'reactstrap' |
||||
import Select from 'react-select' |
||||
import { Button as ButtonP } from 'primereact/button' |
||||
import { isObjEmpty } from '../util' |
||||
import $ from 'jquery' |
||||
import collect from 'collect.js' |
||||
import { setSelectedOpsi } from '../store/KpdlStore' |
||||
import { useDispatch, useSelector } from 'react-redux' |
||||
const NipPengampu = ({ dataSend, setDataSend, activeTab, toast, setHiddenGraphMatoa, dataOpsi }) => { |
||||
const dispatch = useDispatch() |
||||
const storeKpdl = useSelector((state) => state.kpdl) |
||||
|
||||
const [kanwil, setKanwil] = useState({}) |
||||
const [kpp, setKpp] = useState({}) |
||||
const [seksi, setSeksi] = useState([]) |
||||
const [ar, setAr] = useState([]) |
||||
|
||||
const [kanwilSelected, setKanwilSelected] = useState(null) |
||||
const [kppSelected, setKppSelected] = useState({}) |
||||
const [seksiSelected, setSeksiSelected] = useState([]) |
||||
const [arSelected, setArSelected] = useState([]) |
||||
const base_url = '<?=base_url()?>' |
||||
useEffect(() => { |
||||
$.ajax({ |
||||
url: base_url + 'kewilayahan/ref/kanwil', |
||||
method: 'GET', |
||||
dataType: 'json', |
||||
success: (data) => { |
||||
setKanwil(data) |
||||
} |
||||
}) |
||||
}, []) |
||||
|
||||
useEffect(() => { |
||||
setKpp(null) |
||||
setSeksi([]) |
||||
setAr([]) |
||||
setKppSelected(null) |
||||
setSeksiSelected([]) |
||||
setArSelected([]) |
||||
if (kanwilSelected && !isObjEmpty(kanwilSelected)) { |
||||
const kanwil = kanwilSelected.value |
||||
$.ajax({ |
||||
url: base_url + 'kewilayahan/ref/kpp', |
||||
method: 'GET', |
||||
dataType: 'json', |
||||
data: { kanwil }, |
||||
success: (data) => { |
||||
setKpp(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [kanwilSelected]) |
||||
|
||||
useEffect(() => { |
||||
setSeksi([]) |
||||
setAr([]) |
||||
setSeksiSelected([]) |
||||
setArSelected([]) |
||||
if (kppSelected && !isObjEmpty(kppSelected)) { |
||||
const kpp = kppSelected.value |
||||
$.ajax({ |
||||
url: base_url + 'kewilayahan/ref/seksi', |
||||
method: 'GET', |
||||
dataType: 'json', |
||||
data: { kpp }, |
||||
success: (data) => { |
||||
setSeksi(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [kppSelected]) |
||||
|
||||
useEffect(() => { |
||||
setAr([]) |
||||
setArSelected([]) |
||||
const seksi = collect(seksiSelected).pluck('value').all() |
||||
if (seksi.length && !isObjEmpty(seksiSelected)) { |
||||
const kpp = kppSelected.value |
||||
|
||||
$.ajax({ |
||||
url: base_url + 'kewilayahan/ref/ar', |
||||
method: 'POST', |
||||
dataType: 'json', |
||||
data: { kpp, seksi }, |
||||
success: (data) => { |
||||
setAr(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [seksiSelected]) |
||||
const buttonProsesOnClick = () => { |
||||
const nip_ar_pengampu = collect(arSelected).pluck('value').all() |
||||
if (nip_ar_pengampu.length) { |
||||
dispatch(setSelectedOpsi(dataOpsi.pengampu)) |
||||
setDataSend({ opsiWilZona: dataOpsi.pengampu.key, nip_ar_pengampu }) |
||||
setHiddenGraphMatoa(true) |
||||
} else { |
||||
toast.current.show({ severity: 'info', summary: 'Info', detail: 'AR Pengampu harus dipilih' }) |
||||
} |
||||
} |
||||
return ( |
||||
<> |
||||
<Row> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="basicInput"> |
||||
Kanwil |
||||
</Label> |
||||
<Select |
||||
placeholder="Pilih Kanwil" |
||||
className="basic-single w-100" |
||||
onChange={(e) => { |
||||
setKanwilSelected(e) |
||||
}} |
||||
classNamePrefix="select" |
||||
// defaultValue={kanwilSelected}
|
||||
value={kanwilSelected} |
||||
isClearable={false} |
||||
options={kanwil} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih KPP"> |
||||
KPP |
||||
</Label> |
||||
<Select |
||||
placeholder="Pilih KPP" |
||||
className="basic-single w-100" |
||||
onChange={(e) => { |
||||
setKppSelected(e) |
||||
}} |
||||
classNamePrefix="select" |
||||
// defaultValue={kanwilSelected}
|
||||
value={kppSelected} |
||||
isClearable={false} |
||||
options={kpp} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih Seksi"> |
||||
Seksi |
||||
</Label> |
||||
<MultiSelect |
||||
className="me-1 w-full" |
||||
hasSelectAll={true} |
||||
debounceDuration={300} |
||||
options={seksi} |
||||
value={seksiSelected} |
||||
onChange={(e) => { |
||||
setSeksiSelected(e) |
||||
}} |
||||
labelledBy="Pilih Seksi" |
||||
overrideStrings={{ allItemsAreSelected: 'Semua dipilih', selectSomeItems: 'Pilih Seksi' }} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih AR"> |
||||
AR |
||||
</Label> |
||||
<MultiSelect |
||||
className="me-1 w-full" |
||||
hasSelectAll={true} |
||||
debounceDuration={300} |
||||
options={ar} |
||||
value={arSelected} |
||||
onChange={(e) => { |
||||
setArSelected(e) |
||||
}} |
||||
labelledBy="Pilih AR" |
||||
overrideStrings={{ allItemsAreSelected: 'Semua dipilih', selectSomeItems: 'Pilih AR' }} |
||||
/> |
||||
</Col> |
||||
</Row> |
||||
<Row className="mt-2"> |
||||
<Col sm="12"> |
||||
<ButtonP onClick={() => buttonProsesOnClick()} label="Proses" severity="" rounded className="w-10rem text-white text-base" /> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default NipPengampu |
@ -1,189 +0,0 @@
|
||||
import React, { useEffect, useRef, useState } from 'react' |
||||
import { MultiSelect } from 'react-multi-select-component' |
||||
import { Col, Label, Row } from 'reactstrap' |
||||
import Select from 'react-select' |
||||
import { Button as ButtonP } from 'primereact/button' |
||||
import { isObjEmpty } from '../util' |
||||
import $ from 'jquery' |
||||
import collect from 'collect.js' |
||||
import { useDispatch, useSelector } from 'react-redux' |
||||
import { setSelectedOpsi } from '../store/KpdlStore' |
||||
|
||||
const NipPerekam = ({ dataSend, setDataSend, activeTab, toast, setHiddenGraphMatoa, dataOpsi }) => { |
||||
const dispatch = useDispatch() |
||||
const storeKpdl = useSelector((state) => state.kpdl) |
||||
|
||||
const base_url = '<?=base_url()?>' |
||||
|
||||
const [kanwil, setKanwil] = useState({}) |
||||
const [kpp, setKpp] = useState(null) |
||||
const [seksi, setSeksi] = useState([]) |
||||
const [ar, setAr] = useState([]) |
||||
|
||||
const [kanwilSelected, setKanwilSelected] = useState(null) |
||||
const [kppSelected, setKppSelected] = useState() |
||||
const [seksiSelected, setSeksiSelected] = useState([]) |
||||
const [arSelected, setArSelected] = useState([]) |
||||
|
||||
useEffect(() => { |
||||
$.ajax({ |
||||
url: base_url + 'kewilayahan/ref/kanwilPratama', |
||||
method: 'GET', |
||||
dataType: 'json', |
||||
success: (data) => { |
||||
setKanwil(data) |
||||
} |
||||
}) |
||||
}, []) |
||||
|
||||
useEffect(() => { |
||||
setKpp(null) |
||||
setSeksi([]) |
||||
setAr([]) |
||||
setKppSelected(null) |
||||
setSeksiSelected([]) |
||||
setArSelected([]) |
||||
if (kanwilSelected && !isObjEmpty(kanwilSelected)) { |
||||
const kanwil = kanwilSelected.value |
||||
$.ajax({ |
||||
url: base_url + 'kewilayahan/ref/kppPratama', |
||||
method: 'GET', |
||||
dataType: 'json', |
||||
data: { kanwil }, |
||||
success: (data) => { |
||||
setKpp(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [kanwilSelected]) |
||||
|
||||
useEffect(() => { |
||||
setSeksi([]) |
||||
setAr([]) |
||||
setSeksiSelected([]) |
||||
setArSelected([]) |
||||
if (kppSelected && !isObjEmpty(kppSelected)) { |
||||
const kpp = kppSelected.value |
||||
$.ajax({ |
||||
url: base_url + 'kewilayahan/ref/seksi', |
||||
method: 'GET', |
||||
dataType: 'json', |
||||
data: { kpp }, |
||||
success: (data) => { |
||||
setSeksi(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [kppSelected]) |
||||
|
||||
useEffect(() => { |
||||
setAr([]) |
||||
setArSelected([]) |
||||
const seksi = collect(seksiSelected).pluck('value').all() |
||||
if (seksi.length && !isObjEmpty(seksiSelected)) { |
||||
const kpp = kppSelected.value |
||||
// const seksi = collect(seksiSelected).pluck("value").all()
|
||||
|
||||
$.ajax({ |
||||
url: base_url + 'kewilayahan/ref/ar', |
||||
method: 'POST', |
||||
dataType: 'json', |
||||
data: { kpp, seksi }, |
||||
success: (data) => { |
||||
setAr(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [seksiSelected]) |
||||
|
||||
const buttonProsesOnClick = () => { |
||||
const nip_ar_perekam = collect(arSelected).pluck('value').all() |
||||
if (nip_ar_perekam.length) { |
||||
dispatch(setSelectedOpsi(dataOpsi.perekam)) |
||||
setDataSend({ opsiWilZona: dataOpsi.perekam.key, nip_ar_perekam }) |
||||
setHiddenGraphMatoa(true) |
||||
} else { |
||||
toast.current.show({ severity: 'info', summary: 'Info', detail: 'AR Perekam harus dipilih' }) |
||||
} |
||||
} |
||||
return ( |
||||
<> |
||||
<Row> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="basicInput"> |
||||
Kanwil |
||||
</Label> |
||||
<Select |
||||
placeholder="Pilih Kanwil" |
||||
className="basic-single w-100" |
||||
onChange={(e) => { |
||||
setKanwilSelected(e) |
||||
}} |
||||
classNamePrefix="select" |
||||
value={kanwilSelected} |
||||
isClearable={false} |
||||
options={kanwil} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih KPP"> |
||||
KPP |
||||
</Label> |
||||
<Select |
||||
placeholder="Pilih KPP" |
||||
className="basic-single w-100" |
||||
onChange={(e) => { |
||||
setKppSelected(e) |
||||
}} |
||||
classNamePrefix="select" |
||||
// defaultValue={kanwilSelected}
|
||||
value={kppSelected} |
||||
isClearable={false} |
||||
options={kpp} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih Seksi"> |
||||
Seksi |
||||
</Label> |
||||
<MultiSelect |
||||
className="me-1 w-full" |
||||
hasSelectAll={true} |
||||
debounceDuration={300} |
||||
options={seksi} |
||||
value={seksiSelected} |
||||
onChange={(e) => { |
||||
setSeksiSelected(e) |
||||
}} |
||||
labelledBy="Pilih Seksi" |
||||
overrideStrings={{ allItemsAreSelected: 'Semua dipilih', selectSomeItems: 'Pilih Seksi' }} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih AR"> |
||||
AR Perekam |
||||
</Label> |
||||
<MultiSelect |
||||
className="me-1 w-full" |
||||
hasSelectAll={true} |
||||
debounceDuration={300} |
||||
options={ar} |
||||
value={arSelected} |
||||
onChange={(e) => { |
||||
setArSelected(e) |
||||
}} |
||||
labelledBy="Pilih AR" |
||||
overrideStrings={{ allItemsAreSelected: 'Semua dipilih', selectSomeItems: 'Pilih AR' }} |
||||
/> |
||||
</Col> |
||||
</Row> |
||||
<Row className="mt-2"> |
||||
<Col sm="12"> |
||||
<ButtonP onClick={() => buttonProsesOnClick()} label="Proses" severity="" rounded className="w-10rem text-white text-base" /> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default NipPerekam |
@ -1,470 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Col, Row } from 'reactstrap' |
||||
import { Badge } from 'primereact/badge' |
||||
import { Button as ButtonP } from 'primereact/button' |
||||
import { format_angka } from '../util' |
||||
import collect from 'collect.js' |
||||
import $ from 'jquery' |
||||
import 'primereact/resources/themes/bootstrap4-light-blue/theme.css' |
||||
import 'primeflex/primeflex.css' |
||||
|
||||
import { Sidebar } from 'primereact/sidebar' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import { Text } from '@mantine/core' |
||||
|
||||
import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query' |
||||
import dayjs from 'dayjs' |
||||
var relativeTime = require('dayjs/plugin/relativeTime') |
||||
const fetchSize = 101 |
||||
|
||||
const PenugasanKpdl = ({ dataSend }) => { |
||||
const base_url = '<?=base_url()?>' |
||||
|
||||
const refChart = useRef(null) |
||||
const [data, setData] = useState({ |
||||
kpdl: [], |
||||
akum: [], |
||||
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] |
||||
}) |
||||
|
||||
const [selectedBulan, setSelectedBulan] = useState('') |
||||
const [selectedBulanText, setSelectedBulanText] = useState('semua') |
||||
const [bulan, setBulan] = useState([]) |
||||
|
||||
const [visibleSidebar, setVisibleSidebar] = useState(false) |
||||
const [query, setQuery] = useState(null) |
||||
|
||||
useEffect(() => { |
||||
if (selectedBulan != '') { |
||||
$.get({ |
||||
url: base_url + 'kewilayahan/kytp/identifikasiLapangan', |
||||
dataType: 'json', |
||||
type: 'POST', |
||||
data: { |
||||
...dataSend, |
||||
bulan: selectedBulan |
||||
}, |
||||
success: (data) => { |
||||
setData(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [dataSend, selectedBulan]) |
||||
|
||||
useEffect(() => { |
||||
$.get({ |
||||
url: base_url + 'kewilayahan/kytp/getBulan', |
||||
dataType: 'json', |
||||
type: 'GET', |
||||
success: (data) => { |
||||
setBulan(data) |
||||
setSelectedBulan(data[0].value) |
||||
} |
||||
}) |
||||
}, []) |
||||
|
||||
const optionsChart1 = () => { |
||||
return { |
||||
chart: { |
||||
zoomType: 'xy', |
||||
height: '320pt' |
||||
}, |
||||
title: { |
||||
text: '', |
||||
align: 'left' |
||||
}, |
||||
subtitle: { |
||||
align: 'left' |
||||
}, |
||||
xAxis: [ |
||||
{ |
||||
categories: data.categories, |
||||
crosshair: true |
||||
} |
||||
], |
||||
|
||||
yAxis: [ |
||||
{ |
||||
labels: { |
||||
style: { |
||||
color: Highcharts.getOptions().colors[2] |
||||
} |
||||
}, |
||||
title: { |
||||
text: 'Lokasi KPDL', |
||||
style: { |
||||
color: Highcharts.getOptions().colors[2] |
||||
} |
||||
}, |
||||
opposite: true |
||||
}, |
||||
{ |
||||
title: { |
||||
text: 'Lokasi KPDL s.d.', |
||||
style: { |
||||
color: Highcharts.getOptions().colors[0] |
||||
} |
||||
}, |
||||
labels: { |
||||
style: { |
||||
color: Highcharts.getOptions().colors[0] |
||||
} |
||||
}, |
||||
opposite: true |
||||
} |
||||
], |
||||
|
||||
tooltip: { |
||||
shared: true |
||||
}, |
||||
legend: { |
||||
layout: 'horizontal', |
||||
align: 'center', |
||||
|
||||
verticalAlign: 'top', |
||||
backgroundColor: |
||||
Highcharts.defaultOptions.legend.backgroundColor || // theme
|
||||
'rgba(255,255,255,0.25)' |
||||
}, |
||||
plotOptions: { |
||||
series: { |
||||
cursor: 'pointer', |
||||
point: { |
||||
events: { |
||||
click: function () { |
||||
// console.log(this)
|
||||
if (this.series.userOptions.seriesType === 'kpdl_tunggal') { |
||||
setQuery(this.index + 1) |
||||
setVisibleSidebar(true) |
||||
} else { |
||||
return |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
series: [ |
||||
{ |
||||
name: 'Lokasi KPDL', |
||||
seriesType: 'kpdl_tunggal', |
||||
type: 'column', |
||||
yAxis: 0, |
||||
color: Highcharts.getOptions().colors[2], |
||||
data: data.kpdl, |
||||
marker: { |
||||
enabled: true |
||||
}, |
||||
tooltip: { |
||||
valueSuffix: ' Kpdl' |
||||
} |
||||
}, |
||||
|
||||
{ |
||||
name: 'Lokasi KPDL akumulasi', |
||||
seriesType: 'kpdl_akumulasi', |
||||
type: 'spline', |
||||
yAxis: 1, |
||||
data: data.akum, |
||||
marker: { |
||||
enabled: true |
||||
}, |
||||
tooltip: { |
||||
valueSuffix: ' data' |
||||
}, |
||||
visible: false |
||||
} |
||||
] |
||||
} |
||||
} |
||||
|
||||
const refBulanOnClick = (e) => { |
||||
const kodeBulan = e.target.dataset.value |
||||
const labelBulan = e.target.dataset.label |
||||
setSelectedBulan(kodeBulan) |
||||
setSelectedBulanText(labelBulan) |
||||
} |
||||
|
||||
const TableDetailGraph = ({ dataSend, query }) => { |
||||
const tableContainerRef = useRef(null) |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
const [columnFilters, setColumnFilters] = useState([]) |
||||
const [globalFilter, setGlobalFilter] = useState() |
||||
const [sorting, setSorting] = useState([]) |
||||
const base_url = '<?=base_url()?>' |
||||
const { data, fetchNextPage, isError, isFetching, isLoading } = useInfiniteQuery({ |
||||
queryKey: ['table-data', columnFilters, globalFilter, sorting], |
||||
|
||||
queryFn: async ({ pageParam = 0 }) => { |
||||
const url = new URL(base_url + 'kewilayahan/identaktifitashasil/identifikasilapangan/detail') |
||||
url.searchParams.set('start', `${pageParam * fetchSize}`) |
||||
url.searchParams.set('size', `${fetchSize}`) |
||||
url.searchParams.set('filters', JSON.stringify(columnFilters ?? [])) |
||||
url.searchParams.set('globalFilter', globalFilter ?? '') |
||||
url.searchParams.set('sorting', JSON.stringify(sorting ?? [])) |
||||
|
||||
const response = await fetch(url.href, { |
||||
method: 'POST', |
||||
headers: { |
||||
Accept: 'application/json', |
||||
'Content-Type': 'application/json' |
||||
}, |
||||
body: JSON.stringify({ |
||||
query, |
||||
selectedBulan, |
||||
...dataSend |
||||
}) |
||||
}) |
||||
|
||||
const json = await response.json() |
||||
return json |
||||
}, |
||||
getNextPageParam: (_lastGroup, groups) => groups.length, |
||||
keepPreviousData: true, |
||||
refetchOnWindowFocus: false |
||||
}) |
||||
|
||||
const flatData = useMemo(() => data?.pages.flatMap((page) => page.data) ?? [], [data]) |
||||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0 |
||||
const totalFetched = flatData.length |
||||
|
||||
const fetchMoreOnBottomReached = useCallback( |
||||
(containerRefElement) => { |
||||
if (containerRefElement) { |
||||
const { scrollHeight, scrollTop, clientHeight } = containerRefElement |
||||
//once the user has scrolled within 400px of the bottom of the table, fetch more data if we can
|
||||
if (scrollHeight - scrollTop - clientHeight < 400 && !isFetching && totalFetched < totalDBRowCount) { |
||||
fetchNextPage() |
||||
} |
||||
} |
||||
}, |
||||
|
||||
[fetchNextPage, isFetching, totalFetched, totalDBRowCount] |
||||
) |
||||
|
||||
const columns = [ |
||||
{ |
||||
accessorKey: 'NAMA', |
||||
header: 'Nama' |
||||
}, |
||||
|
||||
{ |
||||
accessorKey: 'MERK_USAHA', |
||||
header: 'Merk Usaha' |
||||
}, |
||||
{ |
||||
accessorKey: 'NO_IDENTITAS', |
||||
header: 'No Identitas' |
||||
}, |
||||
{ |
||||
accessorKey: 'NPWP', |
||||
header: 'NPWP', |
||||
enableClickToCopy: true, |
||||
size: 150 |
||||
}, |
||||
{ |
||||
accessorKey: 'ALAMAT', |
||||
header: 'Alamat' |
||||
}, |
||||
{ |
||||
accessorKey: 'KELURAHAN', |
||||
header: 'Wil. Adm.', |
||||
Cell: (data) => { |
||||
const dataRow = data.row.original |
||||
return `${dataRow.KELURAHAN} ${dataRow.KECAMATAN} ${dataRow.KABUPATEN} ${dataRow.PROVINSI}` |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'STATUS_WP_MFWP', |
||||
header: 'Status WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'JNS_WP_MFWP', |
||||
header: 'Jenis WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KANTOR_PENGAMPU', |
||||
header: 'KPP Terdaftar' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_AR_PENGAMPU', |
||||
header: 'AR Pengampu' |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH_PEMBAYARAN_THN_TERAKHIR', |
||||
header: 'Rp', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
size: 100 |
||||
}, |
||||
{ |
||||
accessorKey: 'KETERANGAN', |
||||
header: 'SPT' |
||||
}, |
||||
{ |
||||
accessorKey: 'SUM_NILAI', |
||||
header: 'NILAI DATA', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KPP_ZONA', |
||||
header: 'KPP Lokasi' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_AR_ZONA', |
||||
header: 'AR Wilayah', |
||||
filter: false |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_PEREKAM', |
||||
header: 'Perekam' |
||||
}, |
||||
{ |
||||
accessorKey: 'CREATION_DATE', |
||||
header: 'Tgl Rekam', |
||||
Cell: ({ cell }) => { |
||||
return dayjs(cell.getValue()).format('YYYY-MM-DD HH:mm:ss') |
||||
} |
||||
} |
||||
] |
||||
|
||||
useEffect(() => { |
||||
if (rowVirtualizerInstanceRef.current) { |
||||
try { |
||||
rowVirtualizerInstanceRef.current.scrollToIndex(0) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
} |
||||
}, [sorting, columnFilters, globalFilter]) |
||||
|
||||
//a check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data
|
||||
|
||||
useEffect(() => { |
||||
fetchMoreOnBottomReached(tableContainerRef.current) |
||||
}, [fetchMoreOnBottomReached]) |
||||
|
||||
const table1 = useMantineReactTable({ |
||||
columns, |
||||
data: flatData, |
||||
enablePagination: false, |
||||
enableRowNumbers: true, |
||||
enableRowVirtualization: true, //optional, but recommended if it is likely going to be more than 100 rows
|
||||
manualFiltering: true, |
||||
manualSorting: true, |
||||
mantineTableContainerProps: { |
||||
ref: tableContainerRef, //get access to the table container element
|
||||
sx: { maxHeight: '600px' }, //give the table a max height
|
||||
onScroll: ( |
||||
event //add an event listener to the table container element
|
||||
) => fetchMoreOnBottomReached(event.target) |
||||
}, |
||||
mantineToolbarAlertBannerProps: { |
||||
color: 'red', |
||||
children: 'Error loading data' |
||||
}, |
||||
onColumnFiltersChange: setColumnFilters, |
||||
onGlobalFilterChange: setGlobalFilter, |
||||
onSortingChange: setSorting, |
||||
renderBottomToolbarCustomActions: () => ( |
||||
<Text className="text-sm"> |
||||
Fetched {totalFetched} of {totalDBRowCount} total rows. |
||||
</Text> |
||||
), |
||||
state: { |
||||
columnFilters, |
||||
globalFilter, |
||||
isLoading, |
||||
showAlertBanner: isError, |
||||
showProgressBars: isFetching, |
||||
sorting |
||||
}, |
||||
rowVirtualizerInstanceRef, //get access to the virtualizer instance
|
||||
rowVirtualizerProps: { overscan: 10 }, |
||||
mantineTableBodyCellProps: { className: 'p-1 text-xs' } |
||||
}) |
||||
|
||||
return <MantineReactTable table={table1} /> |
||||
} |
||||
|
||||
const queryClient = new QueryClient() |
||||
|
||||
return ( |
||||
<> |
||||
<Row> |
||||
<Col md="12"> |
||||
<div className="d-flex justify-content-between border-bottom-1 pb-2"> |
||||
<div> |
||||
<span className="mr-2"> Bulan : </span> |
||||
{bulan.map((val, idx) => { |
||||
return ( |
||||
<Badge |
||||
key={idx} |
||||
id={idx} |
||||
data-value={val.value} |
||||
data-label={val.label} |
||||
severity="warning" |
||||
value={val.label} |
||||
className="ref_bulan_a cursor-pointer mr-10" |
||||
onClick={(e) => refBulanOnClick(e)} |
||||
> |
||||
{' '} |
||||
</Badge> |
||||
) |
||||
})} |
||||
</div> |
||||
<div> |
||||
<span>Bulan terpilih: </span> |
||||
<span> {selectedBulanText} </span> |
||||
</div> |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col> |
||||
<HighchartsReact ref={refChart} highcharts={Highcharts} options={optionsChart1()} /> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col> |
||||
<Sidebar |
||||
header={ |
||||
<> |
||||
<h4>Detail Data </h4> |
||||
</> |
||||
} |
||||
visible={visibleSidebar} |
||||
position="bottom" |
||||
onHide={() => setVisibleSidebar(false)} |
||||
style={{ height: 'calc(100vh - 100px)' }} |
||||
blockScroll |
||||
pt={{ header: { className: 'p-1' }, closeButton: { style: { width: '2rem', height: '1rem' } } }} |
||||
> |
||||
<Row> |
||||
<Col> |
||||
<QueryClientProvider client={queryClient}> |
||||
<TableDetailGraph dataSend={dataSend} query={query} /> |
||||
</QueryClientProvider> |
||||
</Col> |
||||
</Row> |
||||
</Sidebar> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default PenugasanKpdl |
@ -1,350 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Col, Row } from 'reactstrap' |
||||
import { format_angka } from '../util' |
||||
import collect from 'collect.js' |
||||
import $ from 'jquery' |
||||
import { Sidebar } from 'primereact/sidebar' |
||||
import '/node_modules/primeflex/primeflex.css' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import { Text } from '@mantine/core' |
||||
|
||||
import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query' |
||||
import dayjs from 'dayjs' |
||||
var relativeTime = require('dayjs/plugin/relativeTime') |
||||
const fetchSize = 101 |
||||
|
||||
const Identifikasi = ({ dataSend }) => { |
||||
const base_url = '<?=base_url()?>' |
||||
const refChart = useRef(null) |
||||
const [dataGraph, setDataGraph] = useState(null) |
||||
const [dataDetail, setDataDetail] = useState({ meta: { data: [], total: 0 } }) |
||||
const [visibleSidebar, setVisibleSidebar] = useState(false) |
||||
const [query, setQuery] = useState(null) |
||||
|
||||
useEffect(() => { |
||||
$.get({ |
||||
url: base_url + 'kewilayahan/kytp/sebaranIdentifikasi', |
||||
dataType: 'json', |
||||
type: 'POST', |
||||
data: { |
||||
...dataSend |
||||
}, |
||||
success: (data) => { |
||||
setDataGraph(data.data) |
||||
} |
||||
}) |
||||
}, [dataSend]) |
||||
|
||||
const optionsChart = (data, title) => { |
||||
const total_wp = collect(data).sum('y') |
||||
return { |
||||
chart: { |
||||
plotBackgroundColor: null, |
||||
plotBorderWidth: null, |
||||
plotShadow: false, |
||||
type: 'pie', |
||||
zoomType: 'xy', |
||||
height: '300' |
||||
}, |
||||
title: { |
||||
text: title, |
||||
style: { fontSize: '10px' } |
||||
}, |
||||
tooltip: { |
||||
pointFormat: '<b>{point.percentage:.1f}%</b><br>: {point.y} dari ' + format_angka(total_wp) + ' total lokasi Matoa' |
||||
}, |
||||
accessibility: { |
||||
point: { |
||||
valueSuffix: '%' |
||||
} |
||||
}, |
||||
plotOptions: { |
||||
pie: { |
||||
allowPointSelect: true, |
||||
cursor: 'pointer', |
||||
dataLabels: { |
||||
enabled: true, |
||||
style: { fontSize: '10px' }, |
||||
// format: "{point.name}: {point.y} <br> {point.percentage:.1f} %"
|
||||
formatter: function () { |
||||
return `${this.key} : ${Number(this.y).toLocaleString('id-ID', { |
||||
minimumFractionDigits: 0, |
||||
maximumFractionDigits: 0 |
||||
})} <br> ${Number(this.percentage).toLocaleString('id-ID')}%` |
||||
} |
||||
} |
||||
}, |
||||
series: { |
||||
cursor: 'pointer', |
||||
point: { |
||||
events: { |
||||
click: function (a) { |
||||
setQuery(this.key) |
||||
setVisibleSidebar(true) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
series: [ |
||||
{ |
||||
name: '', |
||||
data |
||||
} |
||||
] |
||||
} |
||||
} |
||||
|
||||
const TableDetailGraph = ({ dataSend, query }) => { |
||||
const tableContainerRef = useRef(null) |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
const [columnFilters, setColumnFilters] = useState([]) |
||||
const [globalFilter, setGlobalFilter] = useState() |
||||
const [sorting, setSorting] = useState([]) |
||||
const base_url = '<?=base_url()?>' |
||||
const { data, fetchNextPage, isError, isFetching, isLoading } = useInfiniteQuery({ |
||||
queryKey: ['table-data', columnFilters, globalFilter, sorting], |
||||
|
||||
queryFn: async ({ pageParam = 0 }) => { |
||||
const url = new URL(base_url + 'kewilayahan/sebaran/identifikasi/detail') |
||||
url.searchParams.set('start', `${pageParam * fetchSize}`) |
||||
url.searchParams.set('size', `${fetchSize}`) |
||||
url.searchParams.set('filters', JSON.stringify(columnFilters ?? [])) |
||||
url.searchParams.set('globalFilter', globalFilter ?? '') |
||||
url.searchParams.set('sorting', JSON.stringify(sorting ?? [])) |
||||
|
||||
const response = await fetch(url.href, { |
||||
method: 'POST', |
||||
headers: { |
||||
Accept: 'application/json', |
||||
'Content-Type': 'application/json' |
||||
}, |
||||
body: JSON.stringify({ |
||||
query, |
||||
...dataSend |
||||
}) |
||||
}) |
||||
|
||||
const json = await response.json() |
||||
return json |
||||
}, |
||||
getNextPageParam: (_lastGroup, groups) => groups.length, |
||||
keepPreviousData: true, |
||||
refetchOnWindowFocus: false |
||||
}) |
||||
|
||||
const flatData = useMemo(() => data?.pages.flatMap((page) => page.data) ?? [], [data]) |
||||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0 |
||||
const totalFetched = flatData.length |
||||
|
||||
const fetchMoreOnBottomReached = useCallback( |
||||
(containerRefElement) => { |
||||
if (containerRefElement) { |
||||
const { scrollHeight, scrollTop, clientHeight } = containerRefElement |
||||
//once the user has scrolled within 400px of the bottom of the table, fetch more data if we can
|
||||
if (scrollHeight - scrollTop - clientHeight < 400 && !isFetching && totalFetched < totalDBRowCount) { |
||||
fetchNextPage() |
||||
} |
||||
} |
||||
}, |
||||
|
||||
[fetchNextPage, isFetching, totalFetched, totalDBRowCount] |
||||
) |
||||
|
||||
const columns = [ |
||||
{ |
||||
accessorKey: 'NAMA', |
||||
header: 'Nama' |
||||
}, |
||||
|
||||
{ |
||||
accessorKey: 'MERK_USAHA', |
||||
header: 'Merk Usaha' |
||||
}, |
||||
{ |
||||
accessorKey: 'NO_IDENTITAS', |
||||
header: 'No Identitas' |
||||
}, |
||||
{ |
||||
accessorKey: 'NPWP', |
||||
header: 'NPWP', |
||||
enableClickToCopy: true, |
||||
size: 150 |
||||
}, |
||||
{ |
||||
accessorKey: 'ALAMAT', |
||||
header: 'Alamat' |
||||
}, |
||||
{ |
||||
accessorKey: 'KELURAHAN', |
||||
header: 'Wil. Adm.', |
||||
Cell: (data) => { |
||||
const dataRow = data.row.original |
||||
return `${dataRow.KELURAHAN} ${dataRow.KECAMATAN} ${dataRow.KABUPATEN} ${dataRow.PROVINSI}` |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'STATUS_WP_MFWP', |
||||
header: 'Status WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'JNS_WP_MFWP', |
||||
header: 'Jenis WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KANTOR_PENGAMPU', |
||||
header: 'KPP Terdaftar' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_AR_PENGAMPU', |
||||
header: 'AR Pengampu' |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH_PEMBAYARAN_THN_TERAKHIR', |
||||
header: 'Rp', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
size: 100 |
||||
}, |
||||
{ |
||||
accessorKey: 'KETERANGAN', |
||||
header: 'SPT' |
||||
}, |
||||
{ |
||||
accessorKey: 'SUM_NILAI', |
||||
header: 'NILAI DATA', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KPP_ZONA', |
||||
header: 'KPP Lokasi' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_AR_ZONA', |
||||
header: 'AR Wilayah', |
||||
filter: false |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_PEREKAM', |
||||
header: 'Perekam' |
||||
}, |
||||
{ |
||||
accessorKey: 'CREATION_DATE', |
||||
header: 'Tgl Rekam', |
||||
Cell: ({ cell }) => { |
||||
return dayjs(cell.getValue()).format('YYYY-MM-DD HH:mm:ss') |
||||
} |
||||
} |
||||
] |
||||
|
||||
useEffect(() => { |
||||
if (rowVirtualizerInstanceRef.current) { |
||||
try { |
||||
rowVirtualizerInstanceRef.current.scrollToIndex(0) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
} |
||||
}, [sorting, columnFilters, globalFilter]) |
||||
|
||||
//a check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data
|
||||
|
||||
useEffect(() => { |
||||
fetchMoreOnBottomReached(tableContainerRef.current) |
||||
}, [fetchMoreOnBottomReached]) |
||||
|
||||
const table1 = useMantineReactTable({ |
||||
columns, |
||||
data: flatData, |
||||
enablePagination: false, |
||||
enableRowNumbers: true, |
||||
enableRowVirtualization: true, //optional, but recommended if it is likely going to be more than 100 rows
|
||||
manualFiltering: true, |
||||
manualSorting: true, |
||||
mantineTableContainerProps: { |
||||
ref: tableContainerRef, //get access to the table container element
|
||||
sx: { maxHeight: '600px' }, //give the table a max height
|
||||
onScroll: ( |
||||
event //add an event listener to the table container element
|
||||
) => fetchMoreOnBottomReached(event.target) |
||||
}, |
||||
mantineToolbarAlertBannerProps: { |
||||
color: 'red', |
||||
children: 'Error loading data' |
||||
}, |
||||
onColumnFiltersChange: setColumnFilters, |
||||
onGlobalFilterChange: setGlobalFilter, |
||||
onSortingChange: setSorting, |
||||
renderBottomToolbarCustomActions: () => ( |
||||
<Text className="text-sm"> |
||||
Fetched {totalFetched} of {totalDBRowCount} total rows. |
||||
</Text> |
||||
), |
||||
state: { |
||||
columnFilters, |
||||
globalFilter, |
||||
isLoading, |
||||
showAlertBanner: isError, |
||||
showProgressBars: isFetching, |
||||
sorting |
||||
}, |
||||
rowVirtualizerInstanceRef, //get access to the virtualizer instance
|
||||
rowVirtualizerProps: { overscan: 10 }, |
||||
mantineTableBodyCellProps: { className: 'p-1 text-xs' } |
||||
}) |
||||
|
||||
return <MantineReactTable table={table1} /> |
||||
} |
||||
|
||||
const queryClient = new QueryClient() |
||||
|
||||
return ( |
||||
<> |
||||
<Row> |
||||
<Col> |
||||
<HighchartsReact ref={refChart} highcharts={Highcharts} options={optionsChart(dataGraph, 'Identifikasi Lokasi Matoa')} /> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col> |
||||
<Sidebar |
||||
header={ |
||||
<> |
||||
<h4>Detail Data</h4> |
||||
</> |
||||
} |
||||
visible={visibleSidebar} |
||||
position="bottom" |
||||
onHide={() => setVisibleSidebar(false)} |
||||
style={{ height: 'calc(100vh - 100px)' }} |
||||
blockScroll |
||||
pt={{ header: { className: 'p-1' }, closeButton: { style: { width: '2rem', height: '1rem' } } }} |
||||
> |
||||
<Row> |
||||
<Col> |
||||
<QueryClientProvider client={queryClient}> |
||||
<TableDetailGraph dataSend={dataSend} query={query} /> |
||||
</QueryClientProvider> |
||||
</Col> |
||||
</Row> |
||||
</Sidebar> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default Identifikasi |
@ -1,332 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Col, Row } from 'reactstrap' |
||||
import { format_angka } from '../util' |
||||
import collect from 'collect.js' |
||||
import $ from 'jquery' |
||||
|
||||
import { Sidebar } from 'primereact/sidebar' |
||||
import '/node_modules/primeflex/primeflex.css' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import { Text } from '@mantine/core' |
||||
|
||||
import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query' |
||||
import dayjs from 'dayjs' |
||||
var relativeTime = require('dayjs/plugin/relativeTime') |
||||
var customParseFormat = require('dayjs/plugin/customParseFormat') |
||||
const fetchSize = 101 |
||||
|
||||
const JenisStatusWp = ({ dataSend }) => { |
||||
const base_url = '<?=base_url()?>' |
||||
|
||||
const refChart = useRef(null) |
||||
const refChart2 = useRef(null) |
||||
const [dataJenis, setDataJenis] = useState(null) |
||||
const [dataStatus, setDataStatus] = useState(null) |
||||
|
||||
const [visibleSidebar, setVisibleSidebar] = useState(false) |
||||
const [query, setQuery] = useState(null) |
||||
const [jenisStatus, setJenisStatus] = useState('') |
||||
|
||||
useEffect(() => { |
||||
$.get({ |
||||
url: base_url + 'kewilayahan/kytp/sebaranJenisStatusWp', |
||||
dataType: 'json', |
||||
type: 'POST', |
||||
data: { |
||||
...dataSend |
||||
}, |
||||
success: (data) => { |
||||
setDataJenis(data.dataJenis) |
||||
setDataStatus(data.dataStatus) |
||||
} |
||||
}) |
||||
}, [dataSend]) |
||||
|
||||
const optionsChart = (data, title) => { |
||||
const total_wp = collect(data).sum('y') |
||||
return { |
||||
chart: { |
||||
plotBackgroundColor: null, |
||||
plotBorderWidth: null, |
||||
plotShadow: false, |
||||
type: 'pie', |
||||
zoomType: 'xy', |
||||
height: '300' |
||||
}, |
||||
title: { |
||||
text: title, |
||||
style: { fontSize: '10px' } |
||||
}, |
||||
tooltip: { |
||||
pointFormat: '<b>{point.percentage:.1f}%</b><br>: {point.y} dari ' + format_angka(total_wp) + ' total NPWP' |
||||
}, |
||||
accessibility: { |
||||
point: { |
||||
valueSuffix: '%' |
||||
} |
||||
}, |
||||
plotOptions: { |
||||
pie: { |
||||
allowPointSelect: true, |
||||
cursor: 'pointer', |
||||
dataLabels: { |
||||
enabled: true, |
||||
style: { fontSize: '10px' }, |
||||
format: '{point.name}: <br> {point.percentage:.1f} %' |
||||
} |
||||
}, |
||||
series: { |
||||
cursor: 'pointer', |
||||
point: { |
||||
events: { |
||||
click: function () { |
||||
setQuery(this.key) |
||||
setJenisStatus(this.series.name) |
||||
setVisibleSidebar(true) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
series: [ |
||||
{ |
||||
name: title, |
||||
data |
||||
} |
||||
] |
||||
} |
||||
} |
||||
|
||||
const TableDetailGraph = ({ dataSend, query, jenisStatus }) => { |
||||
const tableContainerRef = useRef(null) |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
const [columnFilters, setColumnFilters] = useState([]) |
||||
const [globalFilter, setGlobalFilter] = useState() |
||||
const [sorting, setSorting] = useState([]) |
||||
const base_url = '<?=base_url()?>' |
||||
const { data, fetchNextPage, isError, isFetching, isLoading } = useInfiniteQuery({ |
||||
queryKey: ['table-data', columnFilters, globalFilter, sorting], |
||||
|
||||
queryFn: async ({ pageParam = 0 }) => { |
||||
const url = new URL(base_url + 'kewilayahan/sebaran/jenisstatus/detail') |
||||
url.searchParams.set('start', `${pageParam * fetchSize}`) |
||||
url.searchParams.set('size', `${fetchSize}`) |
||||
url.searchParams.set('filters', JSON.stringify(columnFilters ?? [])) |
||||
url.searchParams.set('globalFilter', globalFilter ?? '') |
||||
url.searchParams.set('sorting', JSON.stringify(sorting ?? [])) |
||||
|
||||
const response = await fetch(url.href, { |
||||
method: 'POST', |
||||
headers: { |
||||
Accept: 'application/json', |
||||
'Content-Type': 'application/json' |
||||
}, |
||||
body: JSON.stringify({ |
||||
query, |
||||
jenisStatus, |
||||
...dataSend |
||||
}) |
||||
}) |
||||
|
||||
const json = await response.json() |
||||
return json |
||||
}, |
||||
getNextPageParam: (_lastGroup, groups) => groups.length, |
||||
keepPreviousData: true, |
||||
refetchOnWindowFocus: false |
||||
}) |
||||
|
||||
const flatData = useMemo(() => data?.pages.flatMap((page) => page.data) ?? [], [data]) |
||||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0 |
||||
const totalFetched = flatData.length |
||||
|
||||
const fetchMoreOnBottomReached = useCallback( |
||||
(containerRefElement) => { |
||||
if (containerRefElement) { |
||||
const { scrollHeight, scrollTop, clientHeight } = containerRefElement |
||||
//once the user has scrolled within 400px of the bottom of the table, fetch more data if we can
|
||||
if (scrollHeight - scrollTop - clientHeight < 400 && !isFetching && totalFetched < totalDBRowCount) { |
||||
fetchNextPage() |
||||
} |
||||
} |
||||
}, |
||||
|
||||
[fetchNextPage, isFetching, totalFetched, totalDBRowCount] |
||||
) |
||||
|
||||
const columns = [ |
||||
{ |
||||
accessorKey: 'NPWP', |
||||
header: 'NPWP', |
||||
enableClickToCopy: true, |
||||
size: 150 |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_WP', |
||||
header: 'Nama' |
||||
}, |
||||
{ |
||||
accessorKey: 'ALAMAT_MFWP', |
||||
header: 'Alamat' |
||||
}, |
||||
{ |
||||
accessorKey: 'KELURAHAN_MFWP', |
||||
header: 'Wil. Adm.', |
||||
Cell: (data) => { |
||||
const dataRow = data.row.original |
||||
return `${dataRow.KELURAHAN_MFWP ?? ''} ${dataRow.KECAMATAN_MFWP ?? ''} ${dataRow.KOTA_MFWP ?? ''} ${dataRow.PROPINSI_MFWP ?? ''}` |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'STATUS_WP_MFWP', |
||||
header: 'Status WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'JNS_WP_MFWP', |
||||
header: 'Jenis WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KANTOR', |
||||
header: 'KPP Terdaftar' |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_AR_MFWP', |
||||
header: 'AR' |
||||
}, |
||||
{ |
||||
accessorKey: 'FLAG_WPS_WPK', |
||||
header: 'WPS/WPK', |
||||
size: 100, |
||||
mantineTableBodyCellProps: { |
||||
align: 'center' |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH_PEMBAYARAN_THN_TERAKHIR', |
||||
header: 'Rp', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
size: 100 |
||||
}, |
||||
{ |
||||
accessorKey: 'KETERANGAN', |
||||
header: 'SPT' |
||||
}, |
||||
{ |
||||
accessorKey: 'TANGGAL_DAFTAR', |
||||
header: 'Tgl Daftar', |
||||
Cell: ({ cell }) => { |
||||
return dayjs(cell.getValue(), 'DD-MMM-YY').format('YYYY-MM-DD') |
||||
} |
||||
} |
||||
] |
||||
|
||||
useEffect(() => { |
||||
if (rowVirtualizerInstanceRef.current) { |
||||
try { |
||||
rowVirtualizerInstanceRef.current.scrollToIndex(0) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
} |
||||
}, [sorting, columnFilters, globalFilter]) |
||||
|
||||
//a check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data
|
||||
|
||||
useEffect(() => { |
||||
fetchMoreOnBottomReached(tableContainerRef.current) |
||||
}, [fetchMoreOnBottomReached]) |
||||
|
||||
const table1 = useMantineReactTable({ |
||||
columns, |
||||
data: flatData, |
||||
enablePagination: false, |
||||
enableRowNumbers: true, |
||||
enableRowVirtualization: true, //optional, but recommended if it is likely going to be more than 100 rows
|
||||
manualFiltering: true, |
||||
manualSorting: true, |
||||
mantineTableContainerProps: { |
||||
ref: tableContainerRef, //get access to the table container element
|
||||
sx: { maxHeight: '600px' }, //give the table a max height
|
||||
onScroll: ( |
||||
event //add an event listener to the table container element
|
||||
) => fetchMoreOnBottomReached(event.target) |
||||
}, |
||||
mantineToolbarAlertBannerProps: { |
||||
color: 'red', |
||||
children: 'Error loading data' |
||||
}, |
||||
onColumnFiltersChange: setColumnFilters, |
||||
onGlobalFilterChange: setGlobalFilter, |
||||
onSortingChange: setSorting, |
||||
renderBottomToolbarCustomActions: () => ( |
||||
<Text className="text-sm"> |
||||
Fetched {totalFetched} of {totalDBRowCount} total rows. |
||||
</Text> |
||||
), |
||||
state: { |
||||
columnFilters, |
||||
globalFilter, |
||||
isLoading, |
||||
showAlertBanner: isError, |
||||
showProgressBars: isFetching, |
||||
sorting |
||||
}, |
||||
rowVirtualizerInstanceRef, //get access to the virtualizer instance
|
||||
rowVirtualizerProps: { overscan: 10 }, |
||||
mantineTableBodyCellProps: { className: 'p-1 text-xs' }, |
||||
mantineTableBodyProps: { className: 'mb-3' } |
||||
}) |
||||
|
||||
return <MantineReactTable table={table1} /> |
||||
} |
||||
|
||||
const queryClient = new QueryClient() |
||||
|
||||
return ( |
||||
<> |
||||
<Row> |
||||
<Col md="6"> |
||||
<HighchartsReact ref={refChart} highcharts={Highcharts} options={optionsChart(dataJenis, 'Jenis WP')} /> |
||||
</Col> |
||||
<Col md="6"> |
||||
<HighchartsReact ref={refChart2} highcharts={Highcharts} options={optionsChart(dataStatus, 'Status WP')} /> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col> |
||||
<Sidebar |
||||
header={ |
||||
<> |
||||
<h4>Detail Data</h4> |
||||
</> |
||||
} |
||||
visible={visibleSidebar} |
||||
position="bottom" |
||||
onHide={() => setVisibleSidebar(false)} |
||||
style={{ height: 'calc(100vh - 100px)' }} |
||||
blockScroll |
||||
pt={{ header: { className: 'p-1' }, closeButton: { style: { width: '2rem', height: '1rem' } } }} |
||||
> |
||||
<Row> |
||||
<Col> |
||||
<QueryClientProvider client={queryClient}> |
||||
<TableDetailGraph dataSend={dataSend} query={query} jenisStatus={jenisStatus} /> |
||||
</QueryClientProvider> |
||||
</Col> |
||||
</Row> |
||||
</Sidebar> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default JenisStatusWp |
@ -1,437 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Col, Row } from 'reactstrap' |
||||
import { format_angka } from '../util' |
||||
import collect from 'collect.js' |
||||
import $ from 'jquery' |
||||
|
||||
import { Sidebar } from 'primereact/sidebar' |
||||
import '/node_modules/primeflex/primeflex.css' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import { Text } from '@mantine/core' |
||||
|
||||
import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query' |
||||
import dayjs from 'dayjs' |
||||
var relativeTime = require('dayjs/plugin/relativeTime') |
||||
var customParseFormat = require('dayjs/plugin/customParseFormat') |
||||
const fetchSize = 101 |
||||
|
||||
const KLU = ({ dataSend }) => { |
||||
const base_url = '<?=base_url()?>' |
||||
|
||||
const refChart = useRef(null) |
||||
const refChart1 = useRef(null) |
||||
const refChart2 = useRef(null) |
||||
const refChart3 = useRef(null) |
||||
const [dataKluTerdaftar, setDataKluTerdaftar] = useState(null) |
||||
const [limaKluTerdaftar, setLimaKluTerdaftar] = useState([]) |
||||
|
||||
const [dataKluYgBayar, setDataKluYgBayar] = useState(null) |
||||
const [limaKluYgBayar, setLimaKluYgBayar] = useState([]) |
||||
|
||||
const [dataKluYgTidakBayar, setDataKluYgTidakBayar] = useState(null) |
||||
const [limaKluYgTidakBayar, setLimaKluYgTidakBayar] = useState([]) |
||||
|
||||
const [dataRupiahBayar, setDataRupiahBayar] = useState(null) |
||||
const [limaRupiahBayar, setLimaRupiahBayar] = useState([]) |
||||
|
||||
const [limaBesar, setLimaBesar] = useState([]) |
||||
|
||||
const [visibleSidebar, setVisibleSidebar] = useState(false) |
||||
const [query, setQuery] = useState(null) |
||||
const [jenisChart, setJenisChart] = useState(null) |
||||
|
||||
useEffect(() => { |
||||
$.get({ |
||||
url: base_url + 'kewilayahan/kytp/sebaranKLU', |
||||
dataType: 'json', |
||||
type: 'POST', |
||||
data: { |
||||
...dataSend |
||||
}, |
||||
success: (resp) => { |
||||
setDataKluTerdaftar(() => { |
||||
const data = resp.dataKluTerdaftar |
||||
const dataRet = [] |
||||
let jmlLainnya = 0 |
||||
|
||||
for (let index = 0; index < data.length; index++) { |
||||
const element = data[index] |
||||
if (index < 5) { |
||||
dataRet.push({ name: element.name, y: element.y, key: element.key }) |
||||
} else { |
||||
jmlLainnya += element.y |
||||
} |
||||
} |
||||
setLimaKluTerdaftar(collect(dataRet).pluck('key').all()) |
||||
dataRet.push({ name: 'Lainnya', y: jmlLainnya, key: "<?=encryptData('lainnya')?>" }) |
||||
return dataRet |
||||
}) |
||||
setDataKluYgBayar(() => { |
||||
const data = resp.dataKluYgBayar |
||||
const dataRet = [] |
||||
let jmlLainnya = 0 |
||||
|
||||
for (let index = 0; index < data.length; index++) { |
||||
const element = data[index] |
||||
if (index < 5) { |
||||
dataRet.push({ name: element.name, y: element.y, key: element.key }) |
||||
} else { |
||||
jmlLainnya += element.y |
||||
} |
||||
} |
||||
setLimaKluYgBayar(collect(dataRet).pluck('key').all()) |
||||
dataRet.push({ name: 'Lainnya', y: jmlLainnya, key: "<?=encryptData('lainnya')?>" }) |
||||
return dataRet |
||||
}) |
||||
|
||||
setDataKluYgTidakBayar(() => { |
||||
const data = resp.dataKluYgTidakBayar |
||||
const dataRet = [] |
||||
let jmlLainnya = 0 |
||||
|
||||
for (let index = 0; index < data.length; index++) { |
||||
const element = data[index] |
||||
if (index < 5) { |
||||
dataRet.push({ name: element.name, y: element.y, key: element.key }) |
||||
} else { |
||||
jmlLainnya += element.y |
||||
} |
||||
} |
||||
setLimaKluYgTidakBayar(collect(dataRet).pluck('key').all()) |
||||
dataRet.push({ name: 'Lainnya', y: jmlLainnya, key: "<?=encryptData('lainnya')?>" }) |
||||
return dataRet |
||||
}) |
||||
|
||||
setDataRupiahBayar(() => { |
||||
const data = resp.dataRupiahBayar |
||||
const dataRet = [] |
||||
let jmlLainnya = 0 |
||||
|
||||
for (let index = 0; index < data.length; index++) { |
||||
const element = data[index] |
||||
if (index < 5) { |
||||
dataRet.push({ name: element.name, y: element.y, key: element.key }) |
||||
} else { |
||||
jmlLainnya += element.y |
||||
} |
||||
} |
||||
setLimaRupiahBayar(collect(dataRet).pluck('key').all()) |
||||
dataRet.push({ name: 'Lainnya', y: jmlLainnya, key: "<?=encryptData('lainnya')?>" }) |
||||
return dataRet |
||||
}) |
||||
} |
||||
}) |
||||
}, [dataSend]) |
||||
|
||||
const optionsChart = (data, title, attribute1, jenisChart) => { |
||||
const total_wp = collect(data).sum('y') |
||||
return { |
||||
chart: { |
||||
plotBackgroundColor: null, |
||||
plotBorderWidth: null, |
||||
plotShadow: false, |
||||
type: 'pie', |
||||
zoomType: 'xy', |
||||
height: '300' |
||||
}, |
||||
title: { |
||||
text: `<u>${title}</u>`, |
||||
style: { fontSize: '14px' }, |
||||
useHTML: true |
||||
}, |
||||
tooltip: { |
||||
pointFormat: '<b>{point.percentage:.1f}%</b><br>: {point.y} dari ' + format_angka(total_wp) + ' total ' + attribute1 |
||||
}, |
||||
accessibility: { |
||||
point: { |
||||
valueSuffix: '%' |
||||
} |
||||
}, |
||||
plotOptions: { |
||||
pie: { |
||||
allowPointSelect: true, |
||||
cursor: 'pointer', |
||||
dataLabels: { |
||||
enabled: true, |
||||
style: { fontSize: '10px' }, |
||||
format: '{point.name}: <br> {point.percentage:.1f} %' |
||||
} |
||||
}, |
||||
series: { |
||||
cursor: 'pointer', |
||||
point: { |
||||
events: { |
||||
click: function () { |
||||
setLimaBesar(collect(this.series.data).pluck('key').all().slice(0, 5)) |
||||
setQuery(this.key) |
||||
setJenisChart(this.series.name) |
||||
setVisibleSidebar(true) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
series: [ |
||||
{ |
||||
name: jenisChart, |
||||
data |
||||
} |
||||
] |
||||
} |
||||
} |
||||
|
||||
const TableDetailGraph = ({ dataSend, query }) => { |
||||
const tableContainerRef = useRef(null) |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
const [columnFilters, setColumnFilters] = useState([]) |
||||
const [globalFilter, setGlobalFilter] = useState() |
||||
const [sorting, setSorting] = useState([]) |
||||
const base_url = '<?=base_url()?>' |
||||
const { data, fetchNextPage, isError, isFetching, isLoading } = useInfiniteQuery({ |
||||
queryKey: ['table-data', columnFilters, globalFilter, sorting], |
||||
|
||||
queryFn: async ({ pageParam = 0 }) => { |
||||
const url = new URL(base_url + 'kewilayahan/sebaran/klu/detail') |
||||
url.searchParams.set('start', `${pageParam * fetchSize}`) |
||||
url.searchParams.set('size', `${fetchSize}`) |
||||
url.searchParams.set('filters', JSON.stringify(columnFilters ?? [])) |
||||
url.searchParams.set('globalFilter', globalFilter ?? '') |
||||
url.searchParams.set('sorting', JSON.stringify(sorting ?? [])) |
||||
|
||||
const response = await fetch(url.href, { |
||||
method: 'POST', |
||||
headers: { |
||||
Accept: 'application/json', |
||||
'Content-Type': 'application/json' |
||||
}, |
||||
body: JSON.stringify({ |
||||
query, |
||||
jenisChart, |
||||
limaBesar, |
||||
...dataSend |
||||
}) |
||||
}) |
||||
|
||||
const json = await response.json() |
||||
return json |
||||
}, |
||||
getNextPageParam: (_lastGroup, groups) => groups.length, |
||||
keepPreviousData: true, |
||||
refetchOnWindowFocus: false |
||||
}) |
||||
|
||||
const flatData = useMemo(() => data?.pages.flatMap((page) => page.data) ?? [], [data]) |
||||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0 |
||||
const totalFetched = flatData.length |
||||
|
||||
const fetchMoreOnBottomReached = useCallback( |
||||
(containerRefElement) => { |
||||
if (containerRefElement) { |
||||
const { scrollHeight, scrollTop, clientHeight } = containerRefElement |
||||
//once the user has scrolled within 400px of the bottom of the table, fetch more data if we can
|
||||
if (scrollHeight - scrollTop - clientHeight < 400 && !isFetching && totalFetched < totalDBRowCount) { |
||||
fetchNextPage() |
||||
} |
||||
} |
||||
}, |
||||
|
||||
[fetchNextPage, isFetching, totalFetched, totalDBRowCount] |
||||
) |
||||
|
||||
const columns = [ |
||||
{ |
||||
accessorKey: 'NPWP', |
||||
header: 'NPWP', |
||||
enableClickToCopy: true, |
||||
size: 150 |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_WP', |
||||
header: 'Nama' |
||||
}, |
||||
{ |
||||
accessorKey: 'ALAMAT_MFWP', |
||||
header: 'Alamat' |
||||
}, |
||||
{ |
||||
accessorKey: 'KELURAHAN_MFWP', |
||||
header: 'Wil. Adm.', |
||||
Cell: (data) => { |
||||
const dataRow = data.row.original |
||||
return `${dataRow.KELURAHAN_MFWP ?? ''} ${dataRow.KECAMATAN_MFWP ?? ''} ${dataRow.KOTA_MFWP ?? ''} ${dataRow.PROPINSI_MFWP ?? ''}` |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'STATUS_WP_MFWP', |
||||
header: 'Status WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'JNS_WP_MFWP', |
||||
header: 'Jenis WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KANTOR', |
||||
header: 'KPP Terdaftar' |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_AR_MFWP', |
||||
header: 'AR' |
||||
}, |
||||
{ |
||||
accessorKey: 'FLAG_WPS_WPK', |
||||
header: 'WPS/WPK', |
||||
size: 100, |
||||
mantineTableBodyCellProps: { |
||||
align: 'center' |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH_PEMBAYARAN_THN_TERAKHIR', |
||||
header: 'Rp', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
size: 100 |
||||
}, |
||||
{ |
||||
accessorKey: 'KETERANGAN', |
||||
header: 'SPT' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_GOLPOK', |
||||
header: 'Golongan Pokok' |
||||
}, |
||||
{ |
||||
accessorKey: 'TANGGAL_DAFTAR', |
||||
header: 'Tgl Daftar', |
||||
Cell: ({ cell }) => { |
||||
return dayjs(cell.getValue(), 'DD-MMM-YY').format('YYYY-MM-DD') |
||||
} |
||||
} |
||||
] |
||||
|
||||
useEffect(() => { |
||||
if (rowVirtualizerInstanceRef.current) { |
||||
try { |
||||
rowVirtualizerInstanceRef.current.scrollToIndex(0) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
} |
||||
}, [sorting, columnFilters, globalFilter]) |
||||
|
||||
//a check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data
|
||||
|
||||
useEffect(() => { |
||||
fetchMoreOnBottomReached(tableContainerRef.current) |
||||
}, [fetchMoreOnBottomReached]) |
||||
|
||||
const table1 = useMantineReactTable({ |
||||
columns, |
||||
data: flatData, |
||||
enablePagination: false, |
||||
enableRowNumbers: true, |
||||
enableRowVirtualization: true, //optional, but recommended if it is likely going to be more than 100 rows
|
||||
manualFiltering: true, |
||||
manualSorting: true, |
||||
mantineTableContainerProps: { |
||||
ref: tableContainerRef, //get access to the table container element
|
||||
sx: { maxHeight: '600px' }, //give the table a max height
|
||||
onScroll: ( |
||||
event //add an event listener to the table container element
|
||||
) => fetchMoreOnBottomReached(event.target) |
||||
}, |
||||
mantineToolbarAlertBannerProps: { |
||||
color: 'red', |
||||
children: 'Error loading data' |
||||
}, |
||||
onColumnFiltersChange: setColumnFilters, |
||||
onGlobalFilterChange: setGlobalFilter, |
||||
onSortingChange: setSorting, |
||||
renderBottomToolbarCustomActions: () => ( |
||||
<Text className="text-sm"> |
||||
Fetched {totalFetched} of {totalDBRowCount} total rows. |
||||
</Text> |
||||
), |
||||
state: { |
||||
columnFilters, |
||||
globalFilter, |
||||
isLoading, |
||||
showAlertBanner: isError, |
||||
showProgressBars: isFetching, |
||||
sorting |
||||
}, |
||||
rowVirtualizerInstanceRef, //get access to the virtualizer instance
|
||||
rowVirtualizerProps: { overscan: 10 }, |
||||
mantineTableBodyCellProps: { className: 'p-1 text-xs' } |
||||
}) |
||||
|
||||
return <MantineReactTable table={table1} /> |
||||
} |
||||
|
||||
const queryClient = new QueryClient() |
||||
|
||||
return ( |
||||
<> |
||||
<Row> |
||||
<Col md="6"> |
||||
<HighchartsReact ref={refChart} highcharts={Highcharts} options={optionsChart(dataKluTerdaftar, 'KLU Terdaftar', 'NPWP', 'dataKluTerdaftar')} /> |
||||
</Col> |
||||
<Col md="6"> |
||||
<HighchartsReact |
||||
ref={refChart3} |
||||
highcharts={Highcharts} |
||||
options={optionsChart(dataRupiahBayar, 'Dominasi KLU berdarkan Jumlah Pembayaran (Rp)', 'Keseluruhan Pembayaran', 'dataRupiahBayar')} |
||||
/> |
||||
</Col> |
||||
<Col md="6"> |
||||
<HighchartsReact |
||||
ref={refChart1} |
||||
highcharts={Highcharts} |
||||
options={optionsChart(dataKluYgBayar, 'Dominasi KLU dengan pembayaran >0', 'NPWP', 'dataKluYgBayar')} |
||||
/> |
||||
</Col> |
||||
<Col md="6"> |
||||
<HighchartsReact |
||||
ref={refChart2} |
||||
highcharts={Highcharts} |
||||
options={optionsChart(dataKluYgTidakBayar, 'Dominasi KLU pembayaran <=0', 'NPWP', 'dataKluYgTidakBayar')} |
||||
/> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col> |
||||
<Sidebar |
||||
header={ |
||||
<> |
||||
<h4>Detail Data</h4> |
||||
</> |
||||
} |
||||
visible={visibleSidebar} |
||||
position="bottom" |
||||
onHide={() => setVisibleSidebar(false)} |
||||
style={{ height: 'calc(100vh - 100px)' }} |
||||
blockScroll |
||||
pt={{ header: { className: 'p-1' }, closeButton: { style: { width: '2rem', height: '1rem' } } }} |
||||
> |
||||
<Row> |
||||
<Col> |
||||
<QueryClientProvider client={queryClient}> |
||||
<TableDetailGraph dataSend={dataSend} query={query} /> |
||||
</QueryClientProvider> |
||||
</Col> |
||||
</Row> |
||||
</Sidebar> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default KLU |
@ -1,367 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Col, Row } from 'reactstrap' |
||||
import { format_angka } from '../util' |
||||
import $ from 'jquery' |
||||
|
||||
import { Skeleton } from 'primereact/skeleton' |
||||
import collect from 'collect.js' |
||||
|
||||
import { Sidebar } from 'primereact/sidebar' |
||||
import '/node_modules/primeflex/primeflex.css' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import { Text } from '@mantine/core' |
||||
|
||||
import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query' |
||||
import dayjs from 'dayjs' |
||||
var relativeTime = require('dayjs/plugin/relativeTime') |
||||
var customParseFormat = require('dayjs/plugin/customParseFormat') |
||||
const fetchSize = 101 |
||||
|
||||
const PayComp = ({ dataSend }) => { |
||||
const base_url = '<?=base_url()?>' |
||||
|
||||
const refChart = useRef(null) |
||||
const refChart1 = useRef(null) |
||||
const refChart2 = useRef(null) |
||||
const [dataC, setDataC] = useState(null) |
||||
const [dataMin1, setDataMin1] = useState(null) |
||||
const [dataMin2, setDataMin2] = useState(null) |
||||
const [loading, setLoading] = useState(false) |
||||
|
||||
const [visibleSidebar, setVisibleSidebar] = useState(false) |
||||
const [query, setQuery] = useState(null) |
||||
const [tahunBulan, setTahunBulan] = useState(null) |
||||
|
||||
const currentMonth = '<?=currentMonth()?>' |
||||
const currentYear = '<?=currentYear()?>' |
||||
|
||||
useEffect(() => { |
||||
setLoading(true) |
||||
$.get({ |
||||
url: base_url + 'kewilayahan/kytp/sebaranPayComp', |
||||
dataType: 'json', |
||||
type: 'POST', |
||||
data: { |
||||
...dataSend, |
||||
tahun: currentYear, |
||||
bulan: currentMonth |
||||
}, |
||||
success: (data) => { |
||||
setDataC(data.dataC) |
||||
setDataMin1(data.dataMin1) |
||||
setDataMin2(data.dataMin2) |
||||
setLoading(false) |
||||
} |
||||
}) |
||||
}, [dataSend]) |
||||
|
||||
const optionsChart = (data, title, type) => { |
||||
const total_wp = collect(data).sum('y') |
||||
return { |
||||
chart: { |
||||
plotBackgroundColor: null, |
||||
plotBorderWidth: null, |
||||
plotShadow: false, |
||||
type: 'pie', |
||||
zoomType: 'xy', |
||||
height: '300' |
||||
}, |
||||
title: { |
||||
text: title, |
||||
style: { fontSize: '10px' } |
||||
}, |
||||
tooltip: { |
||||
pointFormat: '<b>{point.percentage:.1f}%</b><br>Jml NPWP : {point.y} dari ' + format_angka(total_wp) + ' yang terdapat data penerimaannya' |
||||
}, |
||||
accessibility: { |
||||
point: { |
||||
valueSuffix: '%' |
||||
} |
||||
}, |
||||
plotOptions: { |
||||
pie: { |
||||
allowPointSelect: true, |
||||
cursor: 'pointer', |
||||
// colors: warna_garis,
|
||||
dataLabels: { |
||||
enabled: true, |
||||
style: { fontSize: '0.7rem' }, |
||||
format: '{point.name}: <br> {point.percentage:.1f} %' |
||||
} |
||||
//showInLegend: true
|
||||
}, |
||||
series: { |
||||
cursor: 'pointer', |
||||
point: { |
||||
events: { |
||||
click: function (a) { |
||||
setQuery(this.key) |
||||
setTahunBulan(this.thn_bln) |
||||
setVisibleSidebar(true) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
series: [ |
||||
{ |
||||
name: type, |
||||
data |
||||
} |
||||
] |
||||
} |
||||
} |
||||
|
||||
const TableDetailGraph = ({ dataSend, query }) => { |
||||
const tableContainerRef = useRef(null) |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
const [columnFilters, setColumnFilters] = useState([]) |
||||
const [globalFilter, setGlobalFilter] = useState() |
||||
const [sorting, setSorting] = useState([]) |
||||
const base_url = '<?=base_url()?>' |
||||
const { data, fetchNextPage, isError, isFetching, isLoading } = useInfiniteQuery({ |
||||
queryKey: ['table-data', columnFilters, globalFilter, sorting], |
||||
|
||||
queryFn: async ({ pageParam = 0 }) => { |
||||
const url = new URL(base_url + 'kewilayahan/sebaran/paycomp/detail') |
||||
url.searchParams.set('start', `${pageParam * fetchSize}`) |
||||
url.searchParams.set('size', `${fetchSize}`) |
||||
url.searchParams.set('filters', JSON.stringify(columnFilters ?? [])) |
||||
url.searchParams.set('globalFilter', globalFilter ?? '') |
||||
url.searchParams.set('sorting', JSON.stringify(sorting ?? [])) |
||||
|
||||
const response = await fetch(url.href, { |
||||
method: 'POST', |
||||
headers: { |
||||
Accept: 'application/json', |
||||
'Content-Type': 'application/json' |
||||
}, |
||||
body: JSON.stringify({ |
||||
query, |
||||
tahunBulan, |
||||
...dataSend |
||||
}) |
||||
}) |
||||
|
||||
const json = await response.json() |
||||
return json |
||||
}, |
||||
getNextPageParam: (_lastGroup, groups) => groups.length, |
||||
keepPreviousData: true, |
||||
refetchOnWindowFocus: false |
||||
}) |
||||
|
||||
const flatData = useMemo(() => data?.pages.flatMap((page) => page.data) ?? [], [data]) |
||||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0 |
||||
const totalFetched = flatData.length |
||||
|
||||
const fetchMoreOnBottomReached = useCallback( |
||||
(containerRefElement) => { |
||||
if (containerRefElement) { |
||||
const { scrollHeight, scrollTop, clientHeight } = containerRefElement |
||||
//once the user has scrolled within 400px of the bottom of the table, fetch more data if we can
|
||||
if (scrollHeight - scrollTop - clientHeight < 400 && !isFetching && totalFetched < totalDBRowCount) { |
||||
fetchNextPage() |
||||
} |
||||
} |
||||
}, |
||||
|
||||
[fetchNextPage, isFetching, totalFetched, totalDBRowCount] |
||||
) |
||||
|
||||
const columns = [ |
||||
{ |
||||
accessorKey: 'NPWP', |
||||
header: 'NPWP', |
||||
enableClickToCopy: true, |
||||
size: 150 |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_WP', |
||||
header: 'Nama' |
||||
}, |
||||
{ |
||||
accessorKey: 'ALAMAT_MFWP', |
||||
header: 'Alamat' |
||||
}, |
||||
{ |
||||
accessorKey: 'KELURAHAN_MFWP', |
||||
header: 'Wil. Adm.', |
||||
Cell: (data) => { |
||||
const dataRow = data.row.original |
||||
return `${dataRow.KELURAHAN_MFWP ?? ''} ${dataRow.KECAMATAN_MFWP ?? ''} ${dataRow.KOTA_MFWP ?? ''} ${dataRow.PROPINSI_MFWP ?? ''}` |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'STATUS_WP_MFWP', |
||||
header: 'Status WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'JNS_WP_MFWP', |
||||
header: 'Jenis WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KANTOR', |
||||
header: 'KPP Terdaftar' |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_AR_MFWP', |
||||
header: 'AR' |
||||
}, |
||||
{ |
||||
accessorKey: 'FLAG_WPS_WPK', |
||||
header: 'WPS/WPK', |
||||
size: 100, |
||||
mantineTableBodyCellProps: { |
||||
align: 'center' |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'JML', |
||||
header: 'Jml Bulan', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'center' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'center' |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH_PEMBAYARAN_THN_TERAKHIR', |
||||
header: 'Rp', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
size: 100 |
||||
}, |
||||
{ |
||||
accessorKey: 'KETERANGAN', |
||||
header: 'SPT' |
||||
}, |
||||
{ |
||||
accessorKey: 'TANGGAL_DAFTAR', |
||||
header: 'Tgl Daftar', |
||||
Cell: ({ cell }) => { |
||||
return dayjs(cell.getValue(), 'DD-MMM-YY').format('YYYY-MM-DD') |
||||
} |
||||
} |
||||
] |
||||
|
||||
useEffect(() => { |
||||
if (rowVirtualizerInstanceRef.current) { |
||||
try { |
||||
rowVirtualizerInstanceRef.current.scrollToIndex(0) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
} |
||||
}, [sorting, columnFilters, globalFilter]) |
||||
|
||||
//a check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data
|
||||
|
||||
useEffect(() => { |
||||
fetchMoreOnBottomReached(tableContainerRef.current) |
||||
}, [fetchMoreOnBottomReached]) |
||||
|
||||
const table1 = useMantineReactTable({ |
||||
columns, |
||||
data: flatData, |
||||
enablePagination: false, |
||||
enableRowNumbers: true, |
||||
enableRowVirtualization: true, //optional, but recommended if it is likely going to be more than 100 rows
|
||||
manualFiltering: true, |
||||
manualSorting: true, |
||||
mantineTableContainerProps: { |
||||
ref: tableContainerRef, //get access to the table container element
|
||||
sx: { maxHeight: '600px' }, //give the table a max height
|
||||
onScroll: ( |
||||
event //add an event listener to the table container element
|
||||
) => fetchMoreOnBottomReached(event.target) |
||||
}, |
||||
mantineToolbarAlertBannerProps: { |
||||
color: 'red', |
||||
children: 'Error loading data' |
||||
}, |
||||
onColumnFiltersChange: setColumnFilters, |
||||
onGlobalFilterChange: setGlobalFilter, |
||||
onSortingChange: setSorting, |
||||
renderBottomToolbarCustomActions: () => ( |
||||
<Text className="text-sm"> |
||||
Fetched {totalFetched} of {totalDBRowCount} total rows. |
||||
</Text> |
||||
), |
||||
state: { |
||||
columnFilters, |
||||
globalFilter, |
||||
isLoading, |
||||
showAlertBanner: isError, |
||||
showProgressBars: isFetching, |
||||
sorting |
||||
}, |
||||
rowVirtualizerInstanceRef, //get access to the virtualizer instance
|
||||
rowVirtualizerProps: { overscan: 10 }, |
||||
mantineTableBodyCellProps: { className: 'p-1 text-xs' } |
||||
}) |
||||
|
||||
return <MantineReactTable table={table1} /> |
||||
} |
||||
|
||||
const queryClient = new QueryClient() |
||||
return ( |
||||
<> |
||||
{loading ? ( |
||||
<Row> |
||||
<Col md="12"> |
||||
<Skeleton className="" shape="rectangle" height="17rem" width="100%"></Skeleton> |
||||
</Col> |
||||
</Row> |
||||
) : ( |
||||
<Row> |
||||
<Col md="4"> |
||||
<HighchartsReact ref={refChart} highcharts={Highcharts} options={optionsChart(dataC, 's.d. bulan ini', 'C')} /> |
||||
</Col> |
||||
<Col md="4"> |
||||
<HighchartsReact ref={refChart1} highcharts={Highcharts} options={optionsChart(dataMin1, 's.d. bulan lalu', 'Min1')} /> |
||||
</Col> |
||||
<Col md="4"> |
||||
<HighchartsReact ref={refChart2} highcharts={Highcharts} options={optionsChart(dataMin2, 's.d. 2 bulan yang lalu', 'Min2')} /> |
||||
</Col> |
||||
</Row> |
||||
)} |
||||
<Row> |
||||
<Col> |
||||
<Sidebar |
||||
header={ |
||||
<> |
||||
<h4>Detail Data</h4> |
||||
</> |
||||
} |
||||
visible={visibleSidebar} |
||||
position="bottom" |
||||
onHide={() => setVisibleSidebar(false)} |
||||
style={{ height: 'calc(100vh - 100px)' }} |
||||
blockScroll |
||||
pt={{ header: { className: 'p-1' }, closeButton: { style: { width: '2rem', height: '1rem' } } }} |
||||
> |
||||
<Row> |
||||
<Col> |
||||
<QueryClientProvider client={queryClient}> |
||||
<TableDetailGraph dataSend={dataSend} query={query} /> |
||||
</QueryClientProvider> |
||||
</Col> |
||||
</Row> |
||||
</Sidebar> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default PayComp |
@ -1,363 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Col, Row } from 'reactstrap' |
||||
import { format_angka } from '../util' |
||||
import $ from 'jquery' |
||||
|
||||
import { Skeleton } from 'primereact/skeleton' |
||||
import collect from 'collect.js' |
||||
|
||||
import { Sidebar } from 'primereact/sidebar' |
||||
import '/node_modules/primeflex/primeflex.css' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import { Text } from '@mantine/core' |
||||
|
||||
import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query' |
||||
import dayjs from 'dayjs' |
||||
var relativeTime = require('dayjs/plugin/relativeTime') |
||||
var customParseFormat = require('dayjs/plugin/customParseFormat') |
||||
const fetchSize = 101 |
||||
|
||||
const Pembayaran = ({ dataSend }) => { |
||||
const base_url = '<?=base_url()?>' |
||||
|
||||
const refChart = useRef(null) |
||||
const refChart1 = useRef(null) |
||||
const refChart2 = useRef(null) |
||||
const [dataC, setDataC] = useState(null) |
||||
const [dataMin1, setDataMin1] = useState(null) |
||||
const [dataMin2, setDataMin2] = useState(null) |
||||
const [loading, setLoading] = useState(false) |
||||
|
||||
const [visibleSidebar, setVisibleSidebar] = useState(false) |
||||
const [query, setQuery] = useState(null) |
||||
const [tahunBulan, setTahunBulan] = useState(null) |
||||
|
||||
const currentMonth = '<?=currentMonth()?>' |
||||
const currentYear = '<?=currentYear()?>' |
||||
|
||||
useEffect(() => { |
||||
setLoading(true) |
||||
$.get({ |
||||
url: base_url + 'kewilayahan/kytp/sebaranPembayaran', |
||||
dataType: 'json', |
||||
type: 'POST', |
||||
data: { |
||||
...dataSend, |
||||
tahun: currentYear, |
||||
bulan: currentMonth |
||||
}, |
||||
success: (data) => { |
||||
setDataC(data.dataC) |
||||
setDataMin1(data.dataMin1) |
||||
setDataMin2(data.dataMin2) |
||||
setLoading(false) |
||||
} |
||||
}) |
||||
}, [dataSend]) |
||||
|
||||
const optionsChart = (data, title, type) => { |
||||
const total_wp = collect(data).sum('y') |
||||
return { |
||||
chart: { |
||||
plotBackgroundColor: null, |
||||
plotBorderWidth: null, |
||||
plotShadow: false, |
||||
type: 'pie', |
||||
zoomType: 'xy', |
||||
height: '300' |
||||
}, |
||||
title: { |
||||
text: title, |
||||
style: { fontSize: '10px' } |
||||
}, |
||||
tooltip: { |
||||
pointFormat: '<b>{point.percentage:.1f}%</b><br>Jml NPWP : {point.y} dari ' + format_angka(total_wp) |
||||
}, |
||||
accessibility: { |
||||
point: { |
||||
valueSuffix: '%' |
||||
} |
||||
}, |
||||
plotOptions: { |
||||
pie: { |
||||
allowPointSelect: true, |
||||
cursor: 'pointer', |
||||
//colors : warna_garis,
|
||||
dataLabels: { |
||||
enabled: true, |
||||
style: { fontSize: '10px' }, |
||||
format: '{point.name}: <br> {point.percentage:.1f} %' |
||||
} |
||||
// showInLegend: true
|
||||
}, |
||||
series: { |
||||
cursor: 'pointer', |
||||
point: { |
||||
events: { |
||||
click: function (a) { |
||||
setQuery(this.key) |
||||
setTahunBulan(this.thn_bln) |
||||
setVisibleSidebar(true) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
series: [ |
||||
{ |
||||
name: type, |
||||
data |
||||
} |
||||
] |
||||
} |
||||
} |
||||
|
||||
const TableDetailGraph = ({ dataSend, query }) => { |
||||
const tableContainerRef = useRef(null) |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
const [columnFilters, setColumnFilters] = useState([]) |
||||
const [globalFilter, setGlobalFilter] = useState() |
||||
const [sorting, setSorting] = useState([]) |
||||
const base_url = '<?=base_url()?>' |
||||
const { data, fetchNextPage, isError, isFetching, isLoading } = useInfiniteQuery({ |
||||
queryKey: ['table-data', columnFilters, globalFilter, sorting], |
||||
|
||||
queryFn: async ({ pageParam = 0 }) => { |
||||
const url = new URL(base_url + 'kewilayahan/sebaran/pembayaran/detail') |
||||
url.searchParams.set('start', `${pageParam * fetchSize}`) |
||||
url.searchParams.set('size', `${fetchSize}`) |
||||
url.searchParams.set('filters', JSON.stringify(columnFilters ?? [])) |
||||
url.searchParams.set('globalFilter', globalFilter ?? '') |
||||
url.searchParams.set('sorting', JSON.stringify(sorting ?? [])) |
||||
|
||||
const response = await fetch(url.href, { |
||||
method: 'POST', |
||||
headers: { |
||||
Accept: 'application/json', |
||||
'Content-Type': 'application/json' |
||||
}, |
||||
body: JSON.stringify({ |
||||
query, |
||||
tahunBulan, |
||||
...dataSend |
||||
}) |
||||
}) |
||||
|
||||
const json = await response.json() |
||||
return json |
||||
}, |
||||
getNextPageParam: (_lastGroup, groups) => groups.length, |
||||
keepPreviousData: true, |
||||
refetchOnWindowFocus: false |
||||
}) |
||||
|
||||
const flatData = useMemo(() => data?.pages.flatMap((page) => page.data) ?? [], [data]) |
||||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0 |
||||
const totalFetched = flatData.length |
||||
|
||||
const fetchMoreOnBottomReached = useCallback( |
||||
(containerRefElement) => { |
||||
if (containerRefElement) { |
||||
const { scrollHeight, scrollTop, clientHeight } = containerRefElement |
||||
//once the user has scrolled within 400px of the bottom of the table, fetch more data if we can
|
||||
if (scrollHeight - scrollTop - clientHeight < 400 && !isFetching && totalFetched < totalDBRowCount) { |
||||
fetchNextPage() |
||||
} |
||||
} |
||||
}, |
||||
|
||||
[fetchNextPage, isFetching, totalFetched, totalDBRowCount] |
||||
) |
||||
|
||||
const columns = [ |
||||
{ |
||||
accessorKey: 'NPWP', |
||||
header: 'NPWP', |
||||
enableClickToCopy: true, |
||||
size: 150 |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_WP', |
||||
header: 'Nama' |
||||
}, |
||||
{ |
||||
accessorKey: 'ALAMAT_MFWP', |
||||
header: 'Alamat' |
||||
}, |
||||
{ |
||||
accessorKey: 'KELURAHAN_MFWP', |
||||
header: 'Wil. Adm.', |
||||
Cell: (data) => { |
||||
const dataRow = data.row.original |
||||
return `${dataRow.KELURAHAN_MFWP ?? ''} ${dataRow.KECAMATAN_MFWP ?? ''} ${dataRow.KOTA_MFWP ?? ''} ${dataRow.PROPINSI_MFWP ?? ''}` |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'STATUS_WP_MFWP', |
||||
header: 'Status WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'JNS_WP_MFWP', |
||||
header: 'Jenis WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KANTOR', |
||||
header: 'KPP Terdaftar' |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_AR_MFWP', |
||||
header: 'AR' |
||||
}, |
||||
{ |
||||
accessorKey: 'FLAG_WPS_WPK', |
||||
header: 'WPS/WPK', |
||||
size: 100, |
||||
mantineTableBodyCellProps: { |
||||
align: 'center' |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'JML', |
||||
header: 'Rp', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
size: 100 |
||||
}, |
||||
{ |
||||
accessorKey: 'KETERANGAN', |
||||
header: 'SPT' |
||||
}, |
||||
{ |
||||
accessorKey: 'TANGGAL_DAFTAR', |
||||
header: 'Tgl Daftar', |
||||
Cell: ({ cell }) => { |
||||
return dayjs(cell.getValue(), 'DD-MMM-YY').format('YYYY-MM-DD') |
||||
} |
||||
} |
||||
] |
||||
|
||||
useEffect(() => { |
||||
if (rowVirtualizerInstanceRef.current) { |
||||
try { |
||||
rowVirtualizerInstanceRef.current.scrollToIndex(0) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
} |
||||
}, [sorting, columnFilters, globalFilter]) |
||||
|
||||
//a check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data
|
||||
|
||||
useEffect(() => { |
||||
fetchMoreOnBottomReached(tableContainerRef.current) |
||||
}, [fetchMoreOnBottomReached]) |
||||
|
||||
const table1 = useMantineReactTable({ |
||||
columns, |
||||
data: flatData, |
||||
enablePagination: false, |
||||
enableRowNumbers: true, |
||||
enableRowVirtualization: true, //optional, but recommended if it is likely going to be more than 100 rows
|
||||
manualFiltering: true, |
||||
manualSorting: true, |
||||
mantineTableContainerProps: { |
||||
ref: tableContainerRef, //get access to the table container element
|
||||
sx: { maxHeight: '600px' }, //give the table a max height
|
||||
onScroll: ( |
||||
event //add an event listener to the table container element
|
||||
) => fetchMoreOnBottomReached(event.target) |
||||
}, |
||||
mantineToolbarAlertBannerProps: { |
||||
color: 'red', |
||||
children: 'Error loading data' |
||||
}, |
||||
onColumnFiltersChange: setColumnFilters, |
||||
onGlobalFilterChange: setGlobalFilter, |
||||
onSortingChange: setSorting, |
||||
renderBottomToolbarCustomActions: () => ( |
||||
<Text className="text-sm"> |
||||
Fetched {totalFetched} of {totalDBRowCount} total rows. |
||||
</Text> |
||||
), |
||||
state: { |
||||
columnFilters, |
||||
globalFilter, |
||||
isLoading, |
||||
showAlertBanner: isError, |
||||
showProgressBars: isFetching, |
||||
sorting |
||||
}, |
||||
rowVirtualizerInstanceRef, //get access to the virtualizer instance
|
||||
rowVirtualizerProps: { overscan: 10 }, |
||||
mantineTableBodyCellProps: { className: 'p-1 text-xs' } |
||||
}) |
||||
|
||||
return <MantineReactTable table={table1} /> |
||||
} |
||||
|
||||
const queryClient = new QueryClient() |
||||
|
||||
return ( |
||||
<> |
||||
<Row> |
||||
<Col md="4" className=""> |
||||
{loading ? ( |
||||
<div className="text-center"> |
||||
<Skeleton className="" shape="circle" size="15rem"></Skeleton> |
||||
</div> |
||||
) : ( |
||||
<HighchartsReact ref={refChart} highcharts={Highcharts} options={optionsChart(dataC, 's.d. bulan ini', 'C')} /> |
||||
)} |
||||
</Col> |
||||
<Col md="4"> |
||||
{loading ? ( |
||||
<Skeleton className="" shape="circle" size="15rem"></Skeleton> |
||||
) : ( |
||||
<HighchartsReact ref={refChart1} highcharts={Highcharts} options={optionsChart(dataMin1, 's.d. bulan lalu', 'Min1')} /> |
||||
)} |
||||
</Col> |
||||
<Col md="4"> |
||||
{loading ? ( |
||||
<Skeleton className="center text-center" shape="circle" size="15rem"></Skeleton> |
||||
) : ( |
||||
<HighchartsReact ref={refChart2} highcharts={Highcharts} options={optionsChart(dataMin2, 's.d. 2 bulan yang lalu', 'Min2')} /> |
||||
)} |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col> |
||||
<Sidebar |
||||
header={ |
||||
<> |
||||
<h4>Detail Data</h4> |
||||
</> |
||||
} |
||||
visible={visibleSidebar} |
||||
position="bottom" |
||||
onHide={() => setVisibleSidebar(false)} |
||||
style={{ height: 'calc(100vh - 100px)' }} |
||||
blockScroll |
||||
pt={{ header: { className: 'p-1' }, closeButton: { style: { width: '2rem', height: '1rem' } } }} |
||||
> |
||||
<Row> |
||||
<Col> |
||||
<QueryClientProvider client={queryClient}> |
||||
<TableDetailGraph dataSend={dataSend} query={query} /> |
||||
</QueryClientProvider> |
||||
</Col> |
||||
</Row> |
||||
</Sidebar> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default Pembayaran |
@ -1,332 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Col, Row } from 'reactstrap' |
||||
import { format_angka } from '../util' |
||||
import collect from 'collect.js' |
||||
import $ from 'jquery' |
||||
|
||||
import { Sidebar } from 'primereact/sidebar' |
||||
import '/node_modules/primeflex/primeflex.css' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import { Text } from '@mantine/core' |
||||
|
||||
import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query' |
||||
import dayjs from 'dayjs' |
||||
var relativeTime = require('dayjs/plugin/relativeTime') |
||||
var customParseFormat = require('dayjs/plugin/customParseFormat') |
||||
const fetchSize = 101 |
||||
|
||||
const Pengampu = ({ dataSend }) => { |
||||
const base_url = '<?=base_url()?>' |
||||
|
||||
const refChart = useRef(null) |
||||
const refChart2 = useRef(null) |
||||
const [dataAssign, setDataAssign] = useState(null) |
||||
const [dataUnAssign, setDataUnAssign] = useState(null) |
||||
|
||||
const [visibleSidebar, setVisibleSidebar] = useState(false) |
||||
const [query, setQuery] = useState(null) |
||||
const [jenisChart, setJenisChart] = useState(null) |
||||
|
||||
useEffect(() => { |
||||
$.get({ |
||||
url: base_url + 'kewilayahan/kytp/sebaranPengampu', |
||||
dataType: 'json', |
||||
type: 'POST', |
||||
data: { |
||||
...dataSend |
||||
}, |
||||
success: (data) => { |
||||
setDataAssign(data.assign) |
||||
setDataUnAssign(data.unassign) |
||||
} |
||||
}) |
||||
}, [dataSend]) |
||||
|
||||
const optionsChart = (data, title, kode) => { |
||||
const total_wp = collect(data).sum('y') |
||||
return { |
||||
chart: { |
||||
plotBackgroundColor: null, |
||||
plotBorderWidth: null, |
||||
plotShadow: false, |
||||
type: 'pie', |
||||
zoomType: 'xy', |
||||
height: '300' |
||||
}, |
||||
title: { |
||||
text: title, |
||||
style: { fontSize: '10px' } |
||||
}, |
||||
tooltip: { |
||||
pointFormat: '<b>{point.percentage:.1f}%</b><br>: {point.y} dari ' + format_angka(total_wp) + ' total NPWP yang ada' |
||||
}, |
||||
accessibility: { |
||||
point: { |
||||
valueSuffix: '%' |
||||
} |
||||
}, |
||||
plotOptions: { |
||||
pie: { |
||||
allowPointSelect: true, |
||||
cursor: 'pointer', |
||||
dataLabels: { |
||||
enabled: true, |
||||
style: { fontSize: '10px' }, |
||||
format: '{point.name}: <br> {point.percentage:.1f} %' |
||||
} |
||||
}, |
||||
series: { |
||||
cursor: 'pointer', |
||||
point: { |
||||
events: { |
||||
click: function () { |
||||
setQuery(this.key) |
||||
setJenisChart(this.series.name) |
||||
setVisibleSidebar(true) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
series: [ |
||||
{ |
||||
name: kode, |
||||
data |
||||
} |
||||
] |
||||
} |
||||
} |
||||
|
||||
const TableDetailGraph = ({ dataSend, query, jenisChart }) => { |
||||
const tableContainerRef = useRef(null) |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
const [columnFilters, setColumnFilters] = useState([]) |
||||
const [globalFilter, setGlobalFilter] = useState() |
||||
const [sorting, setSorting] = useState([]) |
||||
const base_url = '<?=base_url()?>' |
||||
const { data, fetchNextPage, isError, isFetching, isLoading } = useInfiniteQuery({ |
||||
queryKey: ['table-data', columnFilters, globalFilter, sorting], |
||||
|
||||
queryFn: async ({ pageParam = 0 }) => { |
||||
const url = new URL(base_url + 'kewilayahan/sebaran/pengampu/detail') |
||||
url.searchParams.set('start', `${pageParam * fetchSize}`) |
||||
url.searchParams.set('size', `${fetchSize}`) |
||||
url.searchParams.set('filters', JSON.stringify(columnFilters ?? [])) |
||||
url.searchParams.set('globalFilter', globalFilter ?? '') |
||||
url.searchParams.set('sorting', JSON.stringify(sorting ?? [])) |
||||
|
||||
const response = await fetch(url.href, { |
||||
method: 'POST', |
||||
headers: { |
||||
Accept: 'application/json', |
||||
'Content-Type': 'application/json' |
||||
}, |
||||
body: JSON.stringify({ |
||||
query, |
||||
jenisChart, |
||||
...dataSend |
||||
}) |
||||
}) |
||||
|
||||
const json = await response.json() |
||||
return json |
||||
}, |
||||
getNextPageParam: (_lastGroup, groups) => groups.length, |
||||
keepPreviousData: true, |
||||
refetchOnWindowFocus: false |
||||
}) |
||||
|
||||
const flatData = useMemo(() => data?.pages.flatMap((page) => page.data) ?? [], [data]) |
||||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0 |
||||
const totalFetched = flatData.length |
||||
|
||||
const fetchMoreOnBottomReached = useCallback( |
||||
(containerRefElement) => { |
||||
if (containerRefElement) { |
||||
const { scrollHeight, scrollTop, clientHeight } = containerRefElement |
||||
//once the user has scrolled within 400px of the bottom of the table, fetch more data if we can
|
||||
if (scrollHeight - scrollTop - clientHeight < 400 && !isFetching && totalFetched < totalDBRowCount) { |
||||
fetchNextPage() |
||||
} |
||||
} |
||||
}, |
||||
|
||||
[fetchNextPage, isFetching, totalFetched, totalDBRowCount] |
||||
) |
||||
|
||||
const columns = [ |
||||
{ |
||||
accessorKey: 'NPWP', |
||||
header: 'NPWP', |
||||
enableClickToCopy: true, |
||||
size: 150 |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_WP', |
||||
header: 'Nama' |
||||
}, |
||||
{ |
||||
accessorKey: 'ALAMAT_MFWP', |
||||
header: 'Alamat' |
||||
}, |
||||
{ |
||||
accessorKey: 'KELURAHAN_MFWP', |
||||
header: 'Wil. Adm.', |
||||
Cell: (data) => { |
||||
const dataRow = data.row.original |
||||
return `${dataRow.KELURAHAN_MFWP ?? ''} ${dataRow.KECAMATAN_MFWP ?? ''} ${dataRow.KOTA_MFWP ?? ''} ${dataRow.PROPINSI_MFWP ?? ''}` |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'STATUS_WP_MFWP', |
||||
header: 'Status WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'JNS_WP_MFWP', |
||||
header: 'Jenis WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KANTOR', |
||||
header: 'KPP Terdaftar' |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_AR_MFWP', |
||||
header: 'AR' |
||||
}, |
||||
{ |
||||
accessorKey: 'FLAG_WPS_WPK', |
||||
header: 'WPS/WPK', |
||||
size: 100, |
||||
mantineTableBodyCellProps: { |
||||
align: 'center' |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH_PEMBAYARAN_THN_TERAKHIR', |
||||
header: 'Rp', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
size: 100 |
||||
}, |
||||
{ |
||||
accessorKey: 'KETERANGAN', |
||||
header: 'SPT' |
||||
}, |
||||
{ |
||||
accessorKey: 'TANGGAL_DAFTAR', |
||||
header: 'Tgl Daftar', |
||||
Cell: ({ cell }) => { |
||||
return dayjs(cell.getValue(), 'DD-MMM-YY').format('YYYY-MM-DD') |
||||
} |
||||
} |
||||
] |
||||
|
||||
useEffect(() => { |
||||
if (rowVirtualizerInstanceRef.current) { |
||||
try { |
||||
rowVirtualizerInstanceRef.current.scrollToIndex(0) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
} |
||||
}, [sorting, columnFilters, globalFilter]) |
||||
|
||||
//a check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data
|
||||
|
||||
useEffect(() => { |
||||
fetchMoreOnBottomReached(tableContainerRef.current) |
||||
}, [fetchMoreOnBottomReached]) |
||||
|
||||
const table1 = useMantineReactTable({ |
||||
columns, |
||||
data: flatData, |
||||
enablePagination: false, |
||||
enableRowNumbers: true, |
||||
enableRowVirtualization: true, //optional, but recommended if it is likely going to be more than 100 rows
|
||||
manualFiltering: true, |
||||
manualSorting: true, |
||||
mantineTableContainerProps: { |
||||
ref: tableContainerRef, //get access to the table container element
|
||||
sx: { maxHeight: '600px' }, //give the table a max height
|
||||
onScroll: ( |
||||
event //add an event listener to the table container element
|
||||
) => fetchMoreOnBottomReached(event.target) |
||||
}, |
||||
mantineToolbarAlertBannerProps: { |
||||
color: 'red', |
||||
children: 'Error loading data' |
||||
}, |
||||
onColumnFiltersChange: setColumnFilters, |
||||
onGlobalFilterChange: setGlobalFilter, |
||||
onSortingChange: setSorting, |
||||
renderBottomToolbarCustomActions: () => ( |
||||
<Text className="text-sm"> |
||||
Fetched {totalFetched} of {totalDBRowCount} total rows. |
||||
</Text> |
||||
), |
||||
state: { |
||||
columnFilters, |
||||
globalFilter, |
||||
isLoading, |
||||
showAlertBanner: isError, |
||||
showProgressBars: isFetching, |
||||
sorting |
||||
}, |
||||
rowVirtualizerInstanceRef, //get access to the virtualizer instance
|
||||
rowVirtualizerProps: { overscan: 10 }, |
||||
mantineTableBodyCellProps: { className: 'p-1 text-xs' }, |
||||
mantineTableBodyProps: { className: 'mb-3' } |
||||
}) |
||||
|
||||
return <MantineReactTable table={table1} /> |
||||
} |
||||
|
||||
const queryClient = new QueryClient() |
||||
|
||||
return ( |
||||
<> |
||||
<Row> |
||||
<Col md="6"> |
||||
<HighchartsReact ref={refChart} highcharts={Highcharts} options={optionsChart(dataAssign, 'KPP Terdaftar', 'assign')} /> |
||||
</Col> |
||||
<Col md="6"> |
||||
<HighchartsReact ref={refChart2} highcharts={Highcharts} options={optionsChart(dataUnAssign, 'Status UnAssign', 'unassign')} /> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col> |
||||
<Sidebar |
||||
header={ |
||||
<> |
||||
<h4>Detail Data</h4> |
||||
</> |
||||
} |
||||
visible={visibleSidebar} |
||||
position="bottom" |
||||
onHide={() => setVisibleSidebar(false)} |
||||
style={{ height: 'calc(100vh - 100px)' }} |
||||
blockScroll |
||||
pt={{ header: { className: 'p-1' }, closeButton: { style: { width: '2rem', height: '1rem' } } }} |
||||
> |
||||
<Row> |
||||
<Col> |
||||
<QueryClientProvider client={queryClient}> |
||||
<TableDetailGraph dataSend={dataSend} query={query} jenisChart={jenisChart} /> |
||||
</QueryClientProvider> |
||||
</Col> |
||||
</Row> |
||||
</Sidebar> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default Pengampu |
@ -1,323 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Col, Row } from 'reactstrap' |
||||
import { format_angka } from '../util' |
||||
import collect from 'collect.js' |
||||
import $ from 'jquery' |
||||
|
||||
import { Sidebar } from 'primereact/sidebar' |
||||
import '/node_modules/primeflex/primeflex.css' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import { Text } from '@mantine/core' |
||||
|
||||
import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query' |
||||
import dayjs from 'dayjs' |
||||
var relativeTime = require('dayjs/plugin/relativeTime') |
||||
var customParseFormat = require('dayjs/plugin/customParseFormat') |
||||
const fetchSize = 101 |
||||
|
||||
const SPTTahunan = ({ dataSend }) => { |
||||
const base_url = '<?=base_url()?>' |
||||
|
||||
const refChart = useRef(null) |
||||
const [data, setData] = useState(null) |
||||
|
||||
const [visibleSidebar, setVisibleSidebar] = useState(false) |
||||
const [query, setQuery] = useState(null) |
||||
|
||||
useEffect(() => { |
||||
$.get({ |
||||
url: base_url + 'kewilayahan/kytp/sebaranSPTTahunan', |
||||
dataType: 'json', |
||||
type: 'POST', |
||||
data: { |
||||
...dataSend |
||||
}, |
||||
success: (data) => { |
||||
setData(data.data) |
||||
} |
||||
}) |
||||
}, [dataSend]) |
||||
|
||||
const optionsChart = (data, title) => { |
||||
const total_wp = collect(data).sum('y') |
||||
return { |
||||
chart: { |
||||
plotBackgroundColor: null, |
||||
plotBorderWidth: null, |
||||
plotShadow: false, |
||||
type: 'pie', |
||||
zoomType: 'xy', |
||||
height: '300' |
||||
}, |
||||
title: { |
||||
text: title, |
||||
style: { fontSize: '10px' } |
||||
}, |
||||
tooltip: { |
||||
pointFormat: '<b>{point.percentage:.1f}%</b><br>: {point.y} dari ' + format_angka(total_wp) + ' total NPWP yang ada' |
||||
}, |
||||
accessibility: { |
||||
point: { |
||||
valueSuffix: '%' |
||||
} |
||||
}, |
||||
plotOptions: { |
||||
pie: { |
||||
allowPointSelect: true, |
||||
cursor: 'pointer', |
||||
dataLabels: { |
||||
enabled: true, |
||||
style: { fontSize: '10px' }, |
||||
format: '{point.name}: <br> {point.percentage:.1f} %' |
||||
} |
||||
}, |
||||
series: { |
||||
cursor: 'pointer', |
||||
point: { |
||||
events: { |
||||
click: function (a) { |
||||
setQuery(this.key) |
||||
setVisibleSidebar(true) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
series: [ |
||||
{ |
||||
name: '', |
||||
data |
||||
} |
||||
] |
||||
} |
||||
} |
||||
|
||||
const TableDetailGraph = ({ dataSend, query, tahunBulan }) => { |
||||
const tableContainerRef = useRef(null) |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
const [columnFilters, setColumnFilters] = useState([]) |
||||
const [globalFilter, setGlobalFilter] = useState() |
||||
const [sorting, setSorting] = useState([]) |
||||
const base_url = '<?=base_url()?>' |
||||
const { data, fetchNextPage, isError, isFetching, isLoading } = useInfiniteQuery({ |
||||
queryKey: ['table-data', columnFilters, globalFilter, sorting], |
||||
|
||||
queryFn: async ({ pageParam = 0 }) => { |
||||
const url = new URL(base_url + 'kewilayahan/sebaran/spttahunan/detail') |
||||
url.searchParams.set('start', `${pageParam * fetchSize}`) |
||||
url.searchParams.set('size', `${fetchSize}`) |
||||
url.searchParams.set('filters', JSON.stringify(columnFilters ?? [])) |
||||
url.searchParams.set('globalFilter', globalFilter ?? '') |
||||
url.searchParams.set('sorting', JSON.stringify(sorting ?? [])) |
||||
|
||||
const response = await fetch(url.href, { |
||||
method: 'POST', |
||||
headers: { |
||||
Accept: 'application/json', |
||||
'Content-Type': 'application/json' |
||||
}, |
||||
body: JSON.stringify({ |
||||
query, |
||||
...dataSend |
||||
}) |
||||
}) |
||||
|
||||
const json = await response.json() |
||||
return json |
||||
}, |
||||
getNextPageParam: (_lastGroup, groups) => groups.length, |
||||
keepPreviousData: true, |
||||
refetchOnWindowFocus: false |
||||
}) |
||||
|
||||
const flatData = useMemo(() => data?.pages.flatMap((page) => page.data) ?? [], [data]) |
||||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0 |
||||
const totalFetched = flatData.length |
||||
|
||||
const fetchMoreOnBottomReached = useCallback( |
||||
(containerRefElement) => { |
||||
if (containerRefElement) { |
||||
const { scrollHeight, scrollTop, clientHeight } = containerRefElement |
||||
//once the user has scrolled within 400px of the bottom of the table, fetch more data if we can
|
||||
if (scrollHeight - scrollTop - clientHeight < 400 && !isFetching && totalFetched < totalDBRowCount) { |
||||
fetchNextPage() |
||||
} |
||||
} |
||||
}, |
||||
|
||||
[fetchNextPage, isFetching, totalFetched, totalDBRowCount] |
||||
) |
||||
|
||||
const columns = [ |
||||
{ |
||||
accessorKey: 'NPWP', |
||||
header: 'NPWP', |
||||
enableClickToCopy: true, |
||||
size: 150 |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_WP', |
||||
header: 'Nama' |
||||
}, |
||||
{ |
||||
accessorKey: 'ALAMAT_MFWP', |
||||
header: 'Alamat' |
||||
}, |
||||
{ |
||||
accessorKey: 'KELURAHAN_MFWP', |
||||
header: 'Wil. Adm.', |
||||
Cell: (data) => { |
||||
const dataRow = data.row.original |
||||
return `${dataRow.KELURAHAN_MFWP ?? ''} ${dataRow.KECAMATAN_MFWP ?? ''} ${dataRow.KOTA_MFWP ?? ''} ${dataRow.PROPINSI_MFWP ?? ''}` |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'STATUS_WP_MFWP', |
||||
header: 'Status WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'JNS_WP_MFWP', |
||||
header: 'Jenis WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KANTOR', |
||||
header: 'KPP Terdaftar' |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_AR_MFWP', |
||||
header: 'AR' |
||||
}, |
||||
{ |
||||
accessorKey: 'FLAG_WPS_WPK', |
||||
header: 'WPS/WPK', |
||||
size: 100, |
||||
mantineTableBodyCellProps: { |
||||
align: 'center' |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH_PEMBAYARAN_THN_TERAKHIR', |
||||
header: 'Rp', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
size: 100 |
||||
}, |
||||
{ |
||||
accessorKey: 'KETERANGAN', |
||||
header: 'SPT' |
||||
}, |
||||
{ |
||||
accessorKey: 'TANGGAL_DAFTAR', |
||||
header: 'Tgl Daftar', |
||||
Cell: ({ cell }) => { |
||||
return dayjs(cell.getValue(), 'DD-MMM-YY').format('YYYY-MM-DD') |
||||
} |
||||
} |
||||
] |
||||
|
||||
useEffect(() => { |
||||
if (rowVirtualizerInstanceRef.current) { |
||||
try { |
||||
rowVirtualizerInstanceRef.current.scrollToIndex(0) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
} |
||||
}, [sorting, columnFilters, globalFilter]) |
||||
|
||||
//a check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data
|
||||
|
||||
useEffect(() => { |
||||
fetchMoreOnBottomReached(tableContainerRef.current) |
||||
}, [fetchMoreOnBottomReached]) |
||||
|
||||
const table1 = useMantineReactTable({ |
||||
columns, |
||||
data: flatData, |
||||
enablePagination: false, |
||||
enableRowNumbers: true, |
||||
enableRowVirtualization: true, //optional, but recommended if it is likely going to be more than 100 rows
|
||||
manualFiltering: true, |
||||
manualSorting: true, |
||||
mantineTableContainerProps: { |
||||
ref: tableContainerRef, //get access to the table container element
|
||||
sx: { maxHeight: '600px' }, //give the table a max height
|
||||
onScroll: ( |
||||
event //add an event listener to the table container element
|
||||
) => fetchMoreOnBottomReached(event.target) |
||||
}, |
||||
mantineToolbarAlertBannerProps: { |
||||
color: 'red', |
||||
children: 'Error loading data' |
||||
}, |
||||
onColumnFiltersChange: setColumnFilters, |
||||
onGlobalFilterChange: setGlobalFilter, |
||||
onSortingChange: setSorting, |
||||
renderBottomToolbarCustomActions: () => ( |
||||
<Text className="text-sm"> |
||||
Fetched {totalFetched} of {totalDBRowCount} total rows. |
||||
</Text> |
||||
), |
||||
state: { |
||||
columnFilters, |
||||
globalFilter, |
||||
isLoading, |
||||
showAlertBanner: isError, |
||||
showProgressBars: isFetching, |
||||
sorting |
||||
}, |
||||
rowVirtualizerInstanceRef, //get access to the virtualizer instance
|
||||
rowVirtualizerProps: { overscan: 10 }, |
||||
mantineTableBodyCellProps: { className: 'p-1 text-xs' }, |
||||
mantineTableBodyProps: { className: 'mb-3' } |
||||
}) |
||||
|
||||
return <MantineReactTable table={table1} /> |
||||
} |
||||
|
||||
const queryClient = new QueryClient() |
||||
|
||||
return ( |
||||
<> |
||||
<Row> |
||||
<Col> |
||||
<HighchartsReact ref={refChart} highcharts={Highcharts} options={optionsChart(data, 'SPT Tahunan')} /> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col> |
||||
<Sidebar |
||||
header={ |
||||
<> |
||||
<h4>Detail Data</h4> |
||||
</> |
||||
} |
||||
visible={visibleSidebar} |
||||
position="bottom" |
||||
onHide={() => setVisibleSidebar(false)} |
||||
style={{ height: 'calc(100vh - 100px)' }} |
||||
blockScroll |
||||
pt={{ header: { className: 'p-1' }, closeButton: { style: { width: '2rem', height: '1rem' } } }} |
||||
> |
||||
<Row> |
||||
<Col> |
||||
<QueryClientProvider client={queryClient}> |
||||
<TableDetailGraph dataSend={dataSend} query={query} /> |
||||
</QueryClientProvider> |
||||
</Col> |
||||
</Row> |
||||
</Sidebar> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default SPTTahunan |
@ -1,369 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' |
||||
import { Col, Row, Table } from 'reactstrap' |
||||
import { format_angka } from '../util' |
||||
import collect from 'collect.js' |
||||
import $ from 'jquery' |
||||
import { Skeleton } from 'primereact/skeleton' |
||||
|
||||
import { Sidebar } from 'primereact/sidebar' |
||||
import '/node_modules/primeflex/primeflex.css' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import { Text } from '@mantine/core' |
||||
|
||||
import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query' |
||||
import dayjs from 'dayjs' |
||||
var relativeTime = require('dayjs/plugin/relativeTime') |
||||
var customParseFormat = require('dayjs/plugin/customParseFormat') |
||||
const fetchSize = 101 |
||||
|
||||
const Sof = ({ dataSend }) => { |
||||
const base_url = '<?=base_url()?>' |
||||
|
||||
const [data, setData] = useState([]) |
||||
const [total, setTotal] = useState({ totalC: 0, totalP1: 0, totalP2: 0 }) |
||||
const [loading, setLoading] = useState(false) |
||||
|
||||
const [visibleSidebar, setVisibleSidebar] = useState(false) |
||||
const [query, setQuery] = useState(null) |
||||
const [tahunBulan, setTahunBulan] = useState(null) |
||||
|
||||
const currentMonth = '<?=currentMonth()?>' |
||||
const currentYear = '<?=currentYear()?>' |
||||
|
||||
useEffect(() => { |
||||
setLoading(true) |
||||
$.get({ |
||||
url: base_url + 'kewilayahan/kytp/sebaranSof', |
||||
dataType: 'json', |
||||
type: 'POST', |
||||
data: { |
||||
...dataSend, |
||||
tahun: currentYear, |
||||
bulan: currentMonth |
||||
}, |
||||
success: (data) => { |
||||
setData(data.data) |
||||
setTotal({ |
||||
totalC: collect(data.data).sum('JML_C'), |
||||
totalP1: collect(data.data).sum('JML_P1'), |
||||
totalP2: collect(data.data).sum('JML_P2') |
||||
}) |
||||
setLoading(false) |
||||
} |
||||
}) |
||||
}, [dataSend]) |
||||
|
||||
const angkaOnClick = (key, tahunBulan) => { |
||||
setQuery(key) |
||||
setTahunBulan(tahunBulan) |
||||
setVisibleSidebar(true) |
||||
} |
||||
|
||||
const TableDetailGraph = ({ dataSend, query, tahunBulan }) => { |
||||
const tableContainerRef = useRef(null) |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
const [columnFilters, setColumnFilters] = useState([]) |
||||
const [globalFilter, setGlobalFilter] = useState() |
||||
const [sorting, setSorting] = useState([]) |
||||
const base_url = '<?=base_url()?>' |
||||
const { data, fetchNextPage, isError, isFetching, isLoading } = useInfiniteQuery({ |
||||
queryKey: ['table-data', columnFilters, globalFilter, sorting], |
||||
|
||||
queryFn: async ({ pageParam = 0 }) => { |
||||
const url = new URL(base_url + 'kewilayahan/sebaran/sof/detail') |
||||
url.searchParams.set('start', `${pageParam * fetchSize}`) |
||||
url.searchParams.set('size', `${fetchSize}`) |
||||
url.searchParams.set('filters', JSON.stringify(columnFilters ?? [])) |
||||
url.searchParams.set('globalFilter', globalFilter ?? '') |
||||
url.searchParams.set('sorting', JSON.stringify(sorting ?? [])) |
||||
|
||||
const response = await fetch(url.href, { |
||||
method: 'POST', |
||||
headers: { |
||||
Accept: 'application/json', |
||||
'Content-Type': 'application/json' |
||||
}, |
||||
body: JSON.stringify({ |
||||
query, |
||||
tahunBulan, |
||||
...dataSend |
||||
}) |
||||
}) |
||||
|
||||
const json = await response.json() |
||||
return json |
||||
}, |
||||
getNextPageParam: (_lastGroup, groups) => groups.length, |
||||
keepPreviousData: true, |
||||
refetchOnWindowFocus: false |
||||
}) |
||||
|
||||
const flatData = useMemo(() => data?.pages.flatMap((page) => page.data) ?? [], [data]) |
||||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0 |
||||
const totalFetched = flatData.length |
||||
|
||||
const fetchMoreOnBottomReached = useCallback( |
||||
(containerRefElement) => { |
||||
if (containerRefElement) { |
||||
const { scrollHeight, scrollTop, clientHeight } = containerRefElement |
||||
//once the user has scrolled within 400px of the bottom of the table, fetch more data if we can
|
||||
if (scrollHeight - scrollTop - clientHeight < 400 && !isFetching && totalFetched < totalDBRowCount) { |
||||
fetchNextPage() |
||||
} |
||||
} |
||||
}, |
||||
|
||||
[fetchNextPage, isFetching, totalFetched, totalDBRowCount] |
||||
) |
||||
|
||||
const columns = [ |
||||
{ |
||||
accessorKey: 'NPWP', |
||||
header: 'NPWP', |
||||
enableClickToCopy: true, |
||||
size: 150 |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_WP', |
||||
header: 'Nama' |
||||
}, |
||||
{ |
||||
accessorKey: 'ALAMAT_MFWP', |
||||
header: 'Alamat' |
||||
}, |
||||
{ |
||||
accessorKey: 'KELURAHAN_MFWP', |
||||
header: 'Wil. Adm.', |
||||
Cell: (data) => { |
||||
const dataRow = data.row.original |
||||
return `${dataRow.KELURAHAN_MFWP ?? ''} ${dataRow.KECAMATAN_MFWP ?? ''} ${dataRow.KOTA_MFWP ?? ''} ${dataRow.PROPINSI_MFWP ?? ''}` |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'STATUS_WP_MFWP', |
||||
header: 'Status WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'JNS_WP_MFWP', |
||||
header: 'Jenis WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KANTOR', |
||||
header: 'KPP Terdaftar' |
||||
}, |
||||
{ |
||||
accessorKey: 'NAMA_AR_MFWP', |
||||
header: 'AR' |
||||
}, |
||||
{ |
||||
accessorKey: 'FLAG_WPS_WPK', |
||||
header: 'WPS/WPK', |
||||
size: 100, |
||||
mantineTableBodyCellProps: { |
||||
align: 'center' |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'LAPISAN', |
||||
header: 'Lapisan' |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH_PEMBAYARAN_THN_TERAKHIR', |
||||
header: 'Rp', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
size: 100 |
||||
}, |
||||
{ |
||||
accessorKey: 'KETERANGAN', |
||||
header: 'SPT' |
||||
}, |
||||
{ |
||||
accessorKey: 'TANGGAL_DAFTAR', |
||||
header: 'Tgl Daftar', |
||||
Cell: ({ cell }) => { |
||||
return dayjs(cell.getValue(), 'DD-MMM-YY').format('YYYY-MM-DD') |
||||
} |
||||
} |
||||
] |
||||
|
||||
useEffect(() => { |
||||
if (rowVirtualizerInstanceRef.current) { |
||||
try { |
||||
rowVirtualizerInstanceRef.current.scrollToIndex(0) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
} |
||||
}, [sorting, columnFilters, globalFilter]) |
||||
|
||||
//a check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data
|
||||
|
||||
useEffect(() => { |
||||
fetchMoreOnBottomReached(tableContainerRef.current) |
||||
}, [fetchMoreOnBottomReached]) |
||||
|
||||
const table1 = useMantineReactTable({ |
||||
columns, |
||||
data: flatData, |
||||
enablePagination: false, |
||||
enableRowNumbers: true, |
||||
enableRowVirtualization: true, //optional, but recommended if it is likely going to be more than 100 rows
|
||||
manualFiltering: true, |
||||
manualSorting: true, |
||||
mantineTableContainerProps: { |
||||
ref: tableContainerRef, //get access to the table container element
|
||||
sx: { maxHeight: '600px' }, //give the table a max height
|
||||
onScroll: ( |
||||
event //add an event listener to the table container element
|
||||
) => fetchMoreOnBottomReached(event.target) |
||||
}, |
||||
mantineToolbarAlertBannerProps: { |
||||
color: 'red', |
||||
children: 'Error loading data' |
||||
}, |
||||
onColumnFiltersChange: setColumnFilters, |
||||
onGlobalFilterChange: setGlobalFilter, |
||||
onSortingChange: setSorting, |
||||
renderBottomToolbarCustomActions: () => ( |
||||
<Text className="text-sm"> |
||||
Fetched {totalFetched} of {totalDBRowCount} total rows. |
||||
</Text> |
||||
), |
||||
state: { |
||||
columnFilters, |
||||
globalFilter, |
||||
isLoading, |
||||
showAlertBanner: isError, |
||||
showProgressBars: isFetching, |
||||
sorting |
||||
}, |
||||
rowVirtualizerInstanceRef, //get access to the virtualizer instance
|
||||
rowVirtualizerProps: { overscan: 10 }, |
||||
mantineTableBodyCellProps: { className: 'p-1 text-xs' }, |
||||
mantineTableBodyProps: { className: 'mb-3' } |
||||
}) |
||||
|
||||
return <MantineReactTable table={table1} /> |
||||
} |
||||
|
||||
const queryClient = new QueryClient() |
||||
|
||||
return ( |
||||
<> |
||||
{loading ? ( |
||||
<Row> |
||||
<Col> |
||||
<Skeleton className="" shape="rectangle" height="20rem" width="100%"></Skeleton> |
||||
</Col> |
||||
</Row> |
||||
) : ( |
||||
<Row> |
||||
<Col> |
||||
<div className="d-flex justify-content-center"> |
||||
<Table bordered style={{ width: 'auto', fontSize: '0.85rem' }}> |
||||
<thead className="bg-primary text-white"> |
||||
<tr> |
||||
<th className="text-center text-white" rowSpan="2"> |
||||
Lapisan |
||||
</th> |
||||
<th className="text-center text-white" colSpan="2"> |
||||
s.d Sekarang |
||||
</th> |
||||
<th className="text-center text-white" colSpan="2"> |
||||
s.d Bulan Lalu |
||||
</th> |
||||
<th className="text-center text-white" colSpan="2"> |
||||
s.d 2 Bulan Lalu |
||||
</th> |
||||
</tr> |
||||
<tr> |
||||
<th className="text-center text-white">Jml WP</th> |
||||
<th className="text-center text-white">%</th> |
||||
<th className="text-center text-white">Jml WP</th> |
||||
<th className="text-center text-white">%</th> |
||||
<th className="text-center text-white">Jml WP</th> |
||||
<th className="text-center text-white">%</th> |
||||
</tr> |
||||
<tr className=""> |
||||
<th className="text-center text-white">1</th> |
||||
<th className="text-center text-white">2</th> |
||||
<th className="text-center text-white">3</th> |
||||
<th className="text-center text-white">4</th> |
||||
<th className="text-center text-white">5</th> |
||||
<th className="text-center text-white">6</th> |
||||
<th className="text-center text-white">7</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
{data.map((val, idx) => { |
||||
return ( |
||||
<tr key={idx}> |
||||
<td className="text-start p-1 font-weight-bold">{val.LAPISAN}</td> |
||||
<td className="text-center p-1 cursor-pointer text-blue underline" onClick={() => angkaOnClick(val.key, val.THNBLN_C)}> |
||||
{Number(val.JML_C).toLocaleString('id-ID')} |
||||
</td> |
||||
<td className="text-center p-1">{((val.JML_C / total.totalC) * 100).toFixed(2) + '%'}</td> |
||||
<td className="text-center p-1 cursor-pointer text-blue underline" onClick={() => angkaOnClick(val.key, val.THNBLN_P1)}> |
||||
{Number(val.JML_P1).toLocaleString('id-ID')} |
||||
</td> |
||||
<td className="text-center p-1">{((val.JML_P1 / total.totalP1) * 100).toFixed(2) + '%'}</td> |
||||
<td className="text-center p-1 cursor-pointer text-blue underline" onClick={() => angkaOnClick(val.key, val.THNBLN_P2)}> |
||||
{Number(val.JML_P2).toLocaleString('id-ID')} |
||||
</td> |
||||
<td className="text-center p-1">{((val.JML_P2 / total.totalP2) * 100).toFixed(2) + '%'}</td> |
||||
</tr> |
||||
) |
||||
})} |
||||
</tbody> |
||||
<tfoot> |
||||
<tr className="font-weight-bold"> |
||||
<td className="text-center">Total</td> |
||||
<td className="text-center">{Number(total.totalC).toLocaleString('id-ID')}</td> |
||||
<td className="text-center">100%</td> |
||||
<td className="text-center">{Number(total.totalP1).toLocaleString('id-ID')}</td> |
||||
<td className="text-center">100%</td> |
||||
<td className="text-center">{Number(total.totalP2).toLocaleString('id-ID')}</td> |
||||
<td className="text-center">100%</td> |
||||
</tr> |
||||
</tfoot> |
||||
</Table> |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
)} |
||||
<Row> |
||||
<Col> |
||||
<Sidebar |
||||
header={ |
||||
<> |
||||
<h4>Detail Data</h4> |
||||
</> |
||||
} |
||||
visible={visibleSidebar} |
||||
position="bottom" |
||||
onHide={() => setVisibleSidebar(false)} |
||||
style={{ height: 'calc(100vh - 100px)' }} |
||||
blockScroll |
||||
pt={{ header: { className: 'p-1' }, closeButton: { style: { width: '2rem', height: '1rem' } } }} |
||||
> |
||||
<Row> |
||||
<Col> |
||||
<QueryClientProvider client={queryClient}> |
||||
<TableDetailGraph dataSend={dataSend} query={query} tahunBulan={tahunBulan} /> |
||||
</QueryClientProvider> |
||||
</Col> |
||||
</Row> |
||||
</Sidebar> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default Sof |
@ -1,356 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Col, Row } from 'reactstrap' |
||||
import { format_angka } from '../util' |
||||
import collect from 'collect.js' |
||||
import $ from 'jquery' |
||||
|
||||
import { Sidebar } from 'primereact/sidebar' |
||||
import '/node_modules/primeflex/primeflex.css' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import { Text } from '@mantine/core' |
||||
|
||||
import { QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query' |
||||
import dayjs from 'dayjs' |
||||
var relativeTime = require('dayjs/plugin/relativeTime') |
||||
var customParseFormat = require('dayjs/plugin/customParseFormat') |
||||
const fetchSize = 101 |
||||
|
||||
const ZonaPengawasan = ({ dataSend }) => { |
||||
const base_url = '<?=base_url()?>' |
||||
|
||||
const refChart = useRef(null) |
||||
const refChart2 = useRef(null) |
||||
const [dataAll, setDataAll] = useState(null) |
||||
|
||||
const [visibleSidebar, setVisibleSidebar] = useState(false) |
||||
const [query, setQuery] = useState(null) |
||||
|
||||
useEffect(() => { |
||||
$.get({ |
||||
url: base_url + 'kewilayahan/kytp/sebaranZonaPengawasan', |
||||
dataType: 'json', |
||||
type: 'POST', |
||||
data: { |
||||
...dataSend |
||||
}, |
||||
success: (data) => { |
||||
setDataAll(data.all) |
||||
} |
||||
}) |
||||
}, [dataSend]) |
||||
|
||||
const optionsChart = (data, title) => { |
||||
const total_wp = collect(data).sum('y') |
||||
return { |
||||
chart: { |
||||
plotBackgroundColor: null, |
||||
plotBorderWidth: null, |
||||
plotShadow: false, |
||||
type: 'pie', |
||||
zoomType: 'xy', |
||||
height: '300' |
||||
}, |
||||
title: { |
||||
text: title, |
||||
style: { fontSize: '10px' } |
||||
}, |
||||
tooltip: { |
||||
pointFormat: '<b>{point.percentage:.1f}%</b><br>: {point.y} dari ' + format_angka(total_wp) + ' total Lokasi KPDL' |
||||
}, |
||||
accessibility: { |
||||
point: { |
||||
valueSuffix: '%' |
||||
} |
||||
}, |
||||
plotOptions: { |
||||
pie: { |
||||
allowPointSelect: true, |
||||
cursor: 'pointer', |
||||
dataLabels: { |
||||
enabled: true, |
||||
style: { fontSize: '10px' }, |
||||
format: '{point.name}: <br> {point.percentage:.1f} %' |
||||
} |
||||
}, |
||||
series: { |
||||
cursor: 'pointer', |
||||
point: { |
||||
events: { |
||||
click: function () { |
||||
setQuery(this.key) |
||||
setVisibleSidebar(true) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
series: [ |
||||
{ |
||||
name: '', |
||||
data |
||||
} |
||||
] |
||||
} |
||||
} |
||||
|
||||
const TableDetailGraph = ({ dataSend, query }) => { |
||||
const tableContainerRef = useRef(null) |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
const [columnFilters, setColumnFilters] = useState([]) |
||||
const [globalFilter, setGlobalFilter] = useState() |
||||
const [sorting, setSorting] = useState([]) |
||||
const base_url = '<?=base_url()?>' |
||||
const { data, fetchNextPage, isError, isFetching, isLoading } = useInfiniteQuery({ |
||||
queryKey: ['table-data', columnFilters, globalFilter, sorting], |
||||
|
||||
queryFn: async ({ pageParam = 0 }) => { |
||||
const url = new URL(base_url + 'kewilayahan/sebaran/zonapengawasan/detail') |
||||
url.searchParams.set('start', `${pageParam * fetchSize}`) |
||||
url.searchParams.set('size', `${fetchSize}`) |
||||
url.searchParams.set('filters', JSON.stringify(columnFilters ?? [])) |
||||
url.searchParams.set('globalFilter', globalFilter ?? '') |
||||
url.searchParams.set('sorting', JSON.stringify(sorting ?? [])) |
||||
|
||||
const response = await fetch(url.href, { |
||||
method: 'POST', |
||||
headers: { |
||||
Accept: 'application/json', |
||||
'Content-Type': 'application/json' |
||||
}, |
||||
body: JSON.stringify({ |
||||
query, |
||||
...dataSend |
||||
}) |
||||
}) |
||||
|
||||
const json = await response.json() |
||||
return json |
||||
}, |
||||
getNextPageParam: (_lastGroup, groups) => groups.length, |
||||
keepPreviousData: true, |
||||
refetchOnWindowFocus: false |
||||
}) |
||||
|
||||
const flatData = useMemo(() => data?.pages.flatMap((page) => page.data) ?? [], [data]) |
||||
const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0 |
||||
const totalFetched = flatData.length |
||||
|
||||
const fetchMoreOnBottomReached = useCallback( |
||||
(containerRefElement) => { |
||||
if (containerRefElement) { |
||||
const { scrollHeight, scrollTop, clientHeight } = containerRefElement |
||||
//once the user has scrolled within 400px of the bottom of the table, fetch more data if we can
|
||||
if (scrollHeight - scrollTop - clientHeight < 400 && !isFetching && totalFetched < totalDBRowCount) { |
||||
fetchNextPage() |
||||
} |
||||
} |
||||
}, |
||||
|
||||
[fetchNextPage, isFetching, totalFetched, totalDBRowCount] |
||||
) |
||||
|
||||
const columns = [ |
||||
{ |
||||
accessorKey: 'NAMA', |
||||
header: 'Nama' |
||||
}, |
||||
|
||||
{ |
||||
accessorKey: 'MERK_USAHA', |
||||
header: 'Merk Usaha' |
||||
}, |
||||
{ |
||||
accessorKey: 'NO_IDENTITAS', |
||||
header: 'No Identitas' |
||||
}, |
||||
{ |
||||
accessorKey: 'NPWP', |
||||
header: 'NPWP', |
||||
enableClickToCopy: true, |
||||
size: 150 |
||||
}, |
||||
{ |
||||
accessorKey: 'ALAMAT', |
||||
header: 'Alamat' |
||||
}, |
||||
{ |
||||
accessorKey: 'KELURAHAN', |
||||
header: 'Wil. Adm.', |
||||
Cell: (data) => { |
||||
const dataRow = data.row.original |
||||
return `${dataRow.KELURAHAN} ${dataRow.KECAMATAN} ${dataRow.KABUPATEN} ${dataRow.PROVINSI}` |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'STATUS_WP_MFWP', |
||||
header: 'Status WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'JNS_WP_MFWP', |
||||
header: 'Jenis WP' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KANTOR_PENGAMPU', |
||||
header: 'KPP Terdaftar' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_AR_PENGAMPU', |
||||
header: 'AR Pengampu' |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH_PEMBAYARAN_THN_TERAKHIR', |
||||
header: 'Rp', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
size: 100 |
||||
}, |
||||
{ |
||||
accessorKey: 'KETERANGAN', |
||||
header: 'SPT' |
||||
}, |
||||
{ |
||||
accessorKey: 'SUM_NILAI', |
||||
header: 'NILAI DATA', |
||||
Cell: ({ cell }) => parseFloat(cell.getValue()).toLocaleString('id-ID'), |
||||
mantineTableHeadCellProps: { |
||||
align: 'right' |
||||
}, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_KPP_ZONA', |
||||
header: 'KPP Lokasi' |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_AR_ZONA', |
||||
header: 'AR Wilayah', |
||||
filter: false |
||||
}, |
||||
{ |
||||
accessorKey: 'NM_PEREKAM', |
||||
header: 'Perekam' |
||||
}, |
||||
{ |
||||
accessorKey: 'CREATION_DATE', |
||||
header: 'Tgl Rekam', |
||||
Cell: ({ cell }) => { |
||||
return dayjs(cell.getValue()).format('YYYY-MM-DD HH:mm:ss') |
||||
} |
||||
} |
||||
] |
||||
|
||||
useEffect(() => { |
||||
if (rowVirtualizerInstanceRef.current) { |
||||
try { |
||||
rowVirtualizerInstanceRef.current.scrollToIndex(0) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
} |
||||
}, [sorting, columnFilters, globalFilter]) |
||||
|
||||
//a check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data
|
||||
|
||||
useEffect(() => { |
||||
fetchMoreOnBottomReached(tableContainerRef.current) |
||||
}, [fetchMoreOnBottomReached]) |
||||
|
||||
const table1 = useMantineReactTable({ |
||||
columns, |
||||
data: flatData, |
||||
enablePagination: false, |
||||
enableRowNumbers: true, |
||||
enableRowVirtualization: true, //optional, but recommended if it is likely going to be more than 100 rows
|
||||
manualFiltering: true, |
||||
manualSorting: true, |
||||
mantineTableContainerProps: { |
||||
ref: tableContainerRef, //get access to the table container element
|
||||
sx: { maxHeight: '600px' }, //give the table a max height
|
||||
onScroll: ( |
||||
event //add an event listener to the table container element
|
||||
) => fetchMoreOnBottomReached(event.target) |
||||
}, |
||||
mantineToolbarAlertBannerProps: { |
||||
color: 'red', |
||||
children: 'Error loading data' |
||||
}, |
||||
onColumnFiltersChange: setColumnFilters, |
||||
onGlobalFilterChange: setGlobalFilter, |
||||
onSortingChange: setSorting, |
||||
renderBottomToolbarCustomActions: () => ( |
||||
<Text className="text-sm"> |
||||
Fetched {totalFetched} of {totalDBRowCount} total rows. |
||||
</Text> |
||||
), |
||||
state: { |
||||
columnFilters, |
||||
globalFilter, |
||||
isLoading, |
||||
showAlertBanner: isError, |
||||
showProgressBars: isFetching, |
||||
sorting |
||||
}, |
||||
rowVirtualizerInstanceRef, //get access to the virtualizer instance
|
||||
rowVirtualizerProps: { overscan: 10 }, |
||||
mantineTableBodyCellProps: { className: 'p-1 text-xs' }, |
||||
mantineTableBodyProps: { className: 'mb-3' } |
||||
}) |
||||
|
||||
return <MantineReactTable table={table1} /> |
||||
} |
||||
|
||||
const queryClient = new QueryClient() |
||||
|
||||
return ( |
||||
<> |
||||
<Row className="center"> |
||||
<Col md="12"> |
||||
<HighchartsReact |
||||
ref={refChart} |
||||
highcharts={Highcharts} |
||||
options={optionsChart(dataAll, 'Sebaran Zona Pengawasan yang telah dilakukan kegiatan MATOA/KPDL')} |
||||
/> |
||||
<div className="center text-center"> |
||||
<span className="text-center">Sebaran Lokasi Usaha atas WP Terdaftar</span> |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col> |
||||
<Sidebar |
||||
header={ |
||||
<> |
||||
<h4>Detail Data</h4> |
||||
</> |
||||
} |
||||
visible={visibleSidebar} |
||||
position="bottom" |
||||
onHide={() => setVisibleSidebar(false)} |
||||
style={{ height: 'calc(100vh - 100px)' }} |
||||
blockScroll |
||||
pt={{ header: { className: 'p-1' }, closeButton: { style: { width: '2rem', height: '1rem' } } }} |
||||
> |
||||
<Row> |
||||
<Col> |
||||
<QueryClientProvider client={queryClient}> |
||||
<TableDetailGraph dataSend={dataSend} query={query} /> |
||||
</QueryClientProvider> |
||||
</Col> |
||||
</Row> |
||||
</Sidebar> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default ZonaPengawasan |
@ -1,754 +0,0 @@
|
||||
import React, { useEffect, useRef, useState } from 'react' |
||||
import ReactDOM from 'react-dom' |
||||
import { Card, CardBody, CardHeader, CardText, CardTitle, Col, Label, Nav, NavItem, NavLink, Row, TabContent, TabPane } from 'reactstrap' |
||||
import Select from 'react-select' |
||||
import jquery, { data, getJSON } from 'jquery' |
||||
import collect from 'collect.js' |
||||
import { format_angka, isObjEmpty } from './util' |
||||
import { MultiSelect } from 'react-multi-select-component' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Toast } from 'primereact/toast' |
||||
import { Button as ButtonP } from 'primereact/button' |
||||
import 'primereact/resources/themes/bootstrap4-light-blue/theme.css' |
||||
import 'primeflex/primeflex.css' |
||||
import TabProgresifitas from './TabProgresifitas' |
||||
import TabPenugasan from './TabPenugasan' |
||||
import NipPerekam from './componentDepan/NipPerekam' |
||||
import NipPengampu from './componentDepan/NipPengampu' |
||||
import { Provider, useDispatch, useSelector } from 'react-redux' |
||||
import { store } from './store/store' |
||||
import { setSelectedOpsi } from './store/KpdlStore' |
||||
// import 'bootstrap/dist/css/bootstrap.m in.css';
|
||||
// let datasend = {}
|
||||
|
||||
const Root = () => { |
||||
const base_url = '<?=base_url()?>' |
||||
const refChart1 = useRef(null) |
||||
const toast = useRef(null) |
||||
const dispatch = useDispatch() |
||||
const storeKpdl = useSelector((state) => state.kpdl) |
||||
const [dataOpsi, setDataOpsi] = useState({}) |
||||
const [active, setActive] = useState('zona') |
||||
|
||||
const [hiddenGraphMatoa, setHiddenGraphMatoa] = useState(false) |
||||
|
||||
const toggle = (tab) => { |
||||
setActive(tab) |
||||
} |
||||
|
||||
const [prop, setProp] = useState({}) |
||||
const [kota, setKota] = useState({}) |
||||
const [kec, setKec] = useState([]) |
||||
const [kel, setKel] = useState([]) |
||||
|
||||
const [propSelected, setPropSelected] = useState({}) |
||||
const [kotaSelected, setKotaSelected] = useState({}) |
||||
const [kecSelected, setKecSelected] = useState([]) |
||||
const [kelSelected, setKelSelected] = useState([]) |
||||
|
||||
const [kanwil, setKanwil] = useState({}) |
||||
const [kpp, setKpp] = useState({}) |
||||
const [seksi, setSeksi] = useState([]) |
||||
const [ar, setAr] = useState([]) |
||||
const [zp, setZp] = useState([]) |
||||
|
||||
const [kanwilSelected, setKanwilSelected] = useState({}) |
||||
const [kppSelected, setKppSelected] = useState({}) |
||||
const [seksiSelected, setSeksiSelected] = useState([]) |
||||
const [arSelected, setArSelected] = useState([]) |
||||
const [zpSelected, setZpSelected] = useState([]) |
||||
|
||||
const [dataSend, setDataSend] = useState({ opsiWilZona: null, adm4_pcode: [], id_poly_zona: [], nip_ar_perekam: [], nip_ar_pengampu: [] }) |
||||
const [dataGraphMatoa, setDataGraphMatoa] = useState({ poi_agg: [], kpdl_agg: [] }) |
||||
// let session = null
|
||||
const [session, setSession] = useState({}) |
||||
useEffect(() => { |
||||
// setTimeout(() => {
|
||||
jquery.ajax({ |
||||
url: base_url + 'kewilayahan/ref/user', |
||||
method: 'GET', |
||||
dataType: 'json', |
||||
success: (data) => { |
||||
setSession(data) |
||||
if (data.kppadm === '000') { |
||||
toggle('wilayah') |
||||
} else { |
||||
toggle('zona') |
||||
} |
||||
} |
||||
}) |
||||
// }, 2000)
|
||||
|
||||
jquery.ajax({ |
||||
url: base_url + 'kewilayahan/ref/propinsi', |
||||
method: 'GET', |
||||
dataType: 'json', |
||||
success: (data) => { |
||||
setProp(data) |
||||
} |
||||
}) |
||||
|
||||
jquery.ajax({ |
||||
url: base_url + 'kewilayahan/ref/zpkanwil', |
||||
method: 'GET', |
||||
dataType: 'json', |
||||
success: (data) => { |
||||
setKanwil(data) |
||||
} |
||||
}) |
||||
|
||||
jquery.getJSON(base_url + 'kewilayahan/ref/opsi').then((response) => { |
||||
setDataOpsi(response) |
||||
dispatch(setSelectedOpsi(response.default)) |
||||
}) |
||||
|
||||
let judul = document.getElementById('judul') |
||||
judul.innerHTML = '<h3><b><strong>E-Geospatial Thematic Tax</strong></b></h3>' |
||||
}, []) |
||||
|
||||
useEffect(() => { |
||||
setKota({}) |
||||
setKec([]) |
||||
setKel([]) |
||||
setKotaSelected({}) |
||||
setKecSelected([]) |
||||
setKelSelected([]) |
||||
if (propSelected && !isObjEmpty(propSelected)) { |
||||
const prop = propSelected.value |
||||
jquery.ajax({ |
||||
url: base_url + 'kewilayahan/ref/kota', |
||||
method: 'GET', |
||||
dataType: 'json', |
||||
data: { prop }, |
||||
success: (data) => { |
||||
setKota(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [propSelected]) |
||||
|
||||
useEffect(() => { |
||||
setKec([]) |
||||
setKel([]) |
||||
setKecSelected([]) |
||||
setKelSelected([]) |
||||
if (kotaSelected && !isObjEmpty(kotaSelected)) { |
||||
const kota = kotaSelected.value |
||||
jquery.ajax({ |
||||
url: base_url + 'kewilayahan/ref/kecamatan', |
||||
method: 'GET', |
||||
dataType: 'json', |
||||
data: { kota }, |
||||
success: (data) => { |
||||
setKec(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [kotaSelected]) |
||||
|
||||
useEffect(() => { |
||||
setKel([]) |
||||
setKelSelected([]) |
||||
if (kecSelected.length && !isObjEmpty(kecSelected)) { |
||||
const kec = collect(kecSelected).pluck('value').all() |
||||
jquery.ajax({ |
||||
url: base_url + 'kewilayahan/ref/kelurahan', |
||||
method: 'POST', |
||||
dataType: 'json', |
||||
data: { kec }, |
||||
success: (data) => { |
||||
setKel(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [kecSelected]) |
||||
|
||||
useEffect(() => { |
||||
setKpp(null) |
||||
setSeksi([]) |
||||
setAr([]) |
||||
setZp([]) |
||||
setKppSelected(null) |
||||
setSeksiSelected([]) |
||||
setArSelected([]) |
||||
setZpSelected([]) |
||||
if (kanwilSelected && !isObjEmpty(kanwilSelected)) { |
||||
const kanwil = kanwilSelected.value |
||||
jquery.ajax({ |
||||
url: base_url + 'kewilayahan/ref/zpkpp', |
||||
method: 'POST', |
||||
dataType: 'json', |
||||
data: { kanwil }, |
||||
success: (data) => { |
||||
setKpp(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [kanwilSelected]) |
||||
|
||||
useEffect(() => { |
||||
setSeksi([]) |
||||
setAr([]) |
||||
setZp([]) |
||||
setSeksiSelected([]) |
||||
setArSelected([]) |
||||
setZpSelected([]) |
||||
if (kppSelected && !isObjEmpty(kppSelected)) { |
||||
const kpp = kppSelected.value |
||||
jquery.ajax({ |
||||
url: base_url + 'kewilayahan/ref/zpseksi', |
||||
method: 'POST', |
||||
dataType: 'json', |
||||
data: { kpp }, |
||||
success: (data) => { |
||||
setSeksi(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [kppSelected]) |
||||
|
||||
useEffect(() => { |
||||
setAr([]) |
||||
setZp([]) |
||||
setArSelected([]) |
||||
setZpSelected([]) |
||||
if (seksiSelected && !isObjEmpty(seksiSelected)) { |
||||
const kpp = kppSelected.value |
||||
const seksi = collect(seksiSelected).pluck('value').all() |
||||
|
||||
jquery.ajax({ |
||||
url: base_url + 'kewilayahan/ref/zpar', |
||||
method: 'POST', |
||||
dataType: 'json', |
||||
data: { kpp, seksi }, |
||||
success: (data) => { |
||||
setAr(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [seksiSelected]) |
||||
|
||||
useEffect(() => { |
||||
setZp([]) |
||||
setZpSelected([]) |
||||
if (arSelected && !isObjEmpty(arSelected)) { |
||||
const kpp = kppSelected.value |
||||
const seksi = collect(seksiSelected).pluck('value').all() |
||||
const ar = collect(arSelected).pluck('value').all() |
||||
jquery.ajax({ |
||||
url: base_url + 'kewilayahan/ref/zpzp', |
||||
method: 'POST', |
||||
dataType: 'json', |
||||
data: { kpp, seksi, ar }, |
||||
success: (data) => { |
||||
setZp(data) |
||||
} |
||||
}) |
||||
} |
||||
}, [arSelected]) |
||||
|
||||
const buttonProsesOnClick = () => { |
||||
const opsiWilZona = active |
||||
const adm4_pcode = collect(kelSelected).pluck('value').all() |
||||
const id_poly_zona = collect(zpSelected).pluck('value').all() |
||||
const nip_ar_pengampu = collect().pluck('value').all() |
||||
|
||||
switch (opsiWilZona) { |
||||
case 'wilayah': |
||||
if (adm4_pcode.length) { |
||||
dispatch(setSelectedOpsi(dataOpsi.wilayah)) |
||||
setDataSend({ opsiWilZona: dataOpsi.wilayah.key, adm4_pcode, id_poly_zona: [] }) |
||||
setHiddenGraphMatoa(false) |
||||
} else { |
||||
toast.current.show({ severity: 'info', summary: 'Info', detail: 'Kelurahan harus dipilih' }) |
||||
} |
||||
break |
||||
case 'zona': |
||||
if (id_poly_zona.length) { |
||||
dispatch(setSelectedOpsi(dataOpsi.zona)) |
||||
setDataSend({ opsiWilZona: dataOpsi.zona.key, adm4_pcode: [], id_poly_zona }) |
||||
setHiddenGraphMatoa(false) |
||||
} else { |
||||
toast.current.show({ severity: 'info', summary: 'Info', detail: 'Zona harus dipilih' }) |
||||
} |
||||
break |
||||
|
||||
default: |
||||
break |
||||
} |
||||
} |
||||
|
||||
useEffect(() => {}, [storeKpdl.selectedOpsi]) |
||||
|
||||
useEffect(() => { |
||||
Highcharts.setOptions({ |
||||
accessibility: false, |
||||
lang: { |
||||
decimalPoint: ',', |
||||
thousandsSep: '.', |
||||
numericSymbols: ['rb', 'jt', 'M', 'T', 'P', 'E'] |
||||
}, |
||||
|
||||
tooltip: { |
||||
yDecimals: 2 // If you want to add 2 decimals
|
||||
} |
||||
}) |
||||
jquery.ajax({ |
||||
url: base_url + 'kewilayahan/kytp/graph_matoa', |
||||
dataType: 'json', |
||||
type: 'POST', |
||||
data: { ...dataSend }, |
||||
success: (data) => { |
||||
setDataGraphMatoa(data) |
||||
} |
||||
}) |
||||
}, [dataSend]) |
||||
|
||||
const optionsGraphMatoaAgg = { |
||||
chart: { |
||||
zoomType: 'xy', |
||||
height: '320' |
||||
}, |
||||
title: { |
||||
text: 'Poi Google Vs Matoa', |
||||
style: { fontSize: '14px' } |
||||
}, |
||||
|
||||
xAxis: [ |
||||
{ |
||||
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], |
||||
crosshair: true |
||||
} |
||||
], |
||||
yAxis: [ |
||||
{ |
||||
gridLineWidth: 0, |
||||
title: { |
||||
text: '', |
||||
style: { |
||||
color: Highcharts.getOptions().colors[0] |
||||
} |
||||
}, |
||||
labels: { |
||||
//format: '{value}',
|
||||
style: { |
||||
color: Highcharts.getOptions().colors[0] |
||||
} |
||||
}, |
||||
visible: false |
||||
}, |
||||
{ |
||||
labels: { |
||||
//format: '{value}',
|
||||
style: { |
||||
color: Highcharts.getOptions().colors[1] |
||||
} |
||||
}, |
||||
title: { |
||||
text: 'NPWP Work True', |
||||
style: { |
||||
color: Highcharts.getOptions().colors[1] |
||||
} |
||||
}, |
||||
opposite: true, |
||||
visible: false |
||||
}, |
||||
{ |
||||
gridLineWidth: 0, |
||||
title: { |
||||
text: 'Rupiah', |
||||
style: { |
||||
color: Highcharts.getOptions().colors[2] |
||||
} |
||||
}, |
||||
labels: { |
||||
//format: '{value}',
|
||||
style: { |
||||
color: Highcharts.getOptions().colors[2] |
||||
} |
||||
}, |
||||
opposite: true, |
||||
visible: false |
||||
}, |
||||
{ |
||||
gridLineWidth: 0, |
||||
title: { |
||||
text: '', |
||||
style: { |
||||
color: '#FF0000' |
||||
} |
||||
}, |
||||
labels: { |
||||
//format: '{value}',
|
||||
style: { |
||||
color: '##FF0000' |
||||
} |
||||
}, |
||||
opposite: true |
||||
} |
||||
], |
||||
tooltip: { |
||||
shared: true |
||||
}, |
||||
legend: { |
||||
layout: 'horizontal', |
||||
align: 'center', |
||||
//x: 80,
|
||||
verticalAlign: 'top', |
||||
//y: 55,
|
||||
//floating: true,
|
||||
backgroundColor: |
||||
Highcharts.defaultOptions.legend.backgroundColor || // theme
|
||||
'rgba(255,255,255,0.25)' |
||||
}, |
||||
series: [ |
||||
{ |
||||
color: '#FF0000', |
||||
name: 'Jml PoI', |
||||
type: 'column', |
||||
yAxis: 3, |
||||
data: dataGraphMatoa.poi_agg, |
||||
marker: { |
||||
enabled: true |
||||
}, |
||||
tooltip: { |
||||
valueSuffix: ' PoI' |
||||
} |
||||
}, |
||||
{ |
||||
name: 'Matoa', |
||||
type: 'spline', |
||||
yAxis: 3, |
||||
data: dataGraphMatoa.kpdl_agg, |
||||
marker: { |
||||
enabled: true |
||||
}, |
||||
tooltip: { |
||||
pointFormatter: function () { |
||||
const idx = this.index |
||||
let pct_coverage |
||||
const jml_poi_agg = dataGraphMatoa.poi_agg |
||||
if (jml_poi_agg[idx] && jml_poi_agg[idx] !== 0) { |
||||
pct_coverage = format_angka(parseFloat((parseFloat(this.y) / jml_poi_agg[idx]) * 100).toFixed(2)) + '%' |
||||
} |
||||
|
||||
let s = |
||||
'<span style="color:' + |
||||
this.color + |
||||
'">\u25CF</span> ' + |
||||
this.series.name + |
||||
': <b>' + |
||||
format_angka(this.y) + |
||||
' lokasi kpdl</b> ' + |
||||
(pct_coverage ? '(' + pct_coverage + ')<br>\n' : '<br>') |
||||
return s |
||||
}, |
||||
shared: false |
||||
}, |
||||
visible: true, |
||||
color: '#8000ff' |
||||
} |
||||
] |
||||
} |
||||
|
||||
return ( |
||||
<> |
||||
<Row> |
||||
<Col sm="12"> |
||||
<Card> |
||||
<CardBody> |
||||
<Nav tabs> |
||||
{session.kppadm === '000' ? ( |
||||
<NavItem> |
||||
<NavLink |
||||
style={{ cursor: 'pointer' }} |
||||
active={active === 'wilayah'} |
||||
onClick={() => { |
||||
toggle('wilayah') |
||||
}} |
||||
> |
||||
Wilayah Adm. |
||||
</NavLink> |
||||
</NavItem> |
||||
) : null} |
||||
<NavItem> |
||||
<NavLink |
||||
style={{ cursor: 'pointer' }} |
||||
active={active === 'zona'} |
||||
onClick={() => { |
||||
toggle('zona') |
||||
}} |
||||
> |
||||
Zona Pengawasan |
||||
</NavLink> |
||||
</NavItem> |
||||
<NavItem> |
||||
<NavLink |
||||
style={{ cursor: 'pointer' }} |
||||
active={active === 'perekam'} |
||||
onClick={() => { |
||||
toggle('perekam') |
||||
}} |
||||
> |
||||
Perekam |
||||
</NavLink> |
||||
</NavItem> |
||||
<NavItem> |
||||
<NavLink |
||||
style={{ cursor: 'pointer' }} |
||||
active={active === 'pengampu'} |
||||
onClick={() => { |
||||
toggle('pengampu') |
||||
}} |
||||
> |
||||
Pengampu |
||||
</NavLink> |
||||
</NavItem> |
||||
</Nav> |
||||
<TabContent className="py-3" activeTab={active}> |
||||
<TabPane tabId="wilayah"> |
||||
<Row> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="basicInput"> |
||||
Propinsi |
||||
</Label> |
||||
<Select |
||||
placeholder="Pilih Propinsi" |
||||
className="basic-single w-100" |
||||
onChange={(e) => { |
||||
setPropSelected(e) |
||||
}} |
||||
classNamePrefix="select" |
||||
defaultValue={propSelected} |
||||
value={propSelected} |
||||
isClearable={false} |
||||
options={prop} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="basicInput"> |
||||
Kota/Kab |
||||
</Label> |
||||
<Select |
||||
placeholder="Pilih Kota/Kab" |
||||
className="basic-single w-100" |
||||
onChange={(e) => { |
||||
setKotaSelected(e) |
||||
}} |
||||
classNamePrefix="select" |
||||
defaultValue={kotaSelected} |
||||
value={kotaSelected} |
||||
isClearable={false} |
||||
options={kota} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih Kecamatan"> |
||||
Kecamatan |
||||
</Label> |
||||
<MultiSelect |
||||
className="me-1 w-full" |
||||
hasSelectAll={true} |
||||
debounceDuration={300} |
||||
options={kec} |
||||
value={kecSelected} |
||||
onChange={(e) => { |
||||
setKecSelected(e) |
||||
}} |
||||
labelledBy="Pilih Kecamatan" |
||||
overrideStrings={{ allItemsAreSelected: 'Semua dipilih', selectSomeItems: 'Pilih Kecamatan' }} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih Kelurahan"> |
||||
Kelurahan |
||||
</Label> |
||||
<MultiSelect |
||||
className="me-1 w-full" |
||||
hasSelectAll={true} |
||||
debounceDuration={300} |
||||
options={kel} |
||||
value={kelSelected} |
||||
onChange={(e) => { |
||||
setKelSelected(e) |
||||
}} |
||||
labelledBy="Pilih Kelurahan" |
||||
overrideStrings={{ allItemsAreSelected: 'Semua dipilih', selectSomeItems: 'Pilih Kelurahan' }} |
||||
/> |
||||
</Col> |
||||
</Row> |
||||
<Row className="mt-2"> |
||||
<Col sm="12"> |
||||
<ButtonP onClick={() => buttonProsesOnClick()} label="Proses" severity="" rounded className="w-10rem text-white text-base" /> |
||||
</Col> |
||||
</Row> |
||||
</TabPane> |
||||
<TabPane tabId="zona"> |
||||
<Row> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="basicInput"> |
||||
Kanwil |
||||
</Label> |
||||
<Select |
||||
placeholder="Pilih Kanwil" |
||||
className="basic-single w-100" |
||||
onChange={(e) => { |
||||
setKanwilSelected(e) |
||||
}} |
||||
classNamePrefix="select" |
||||
// defaultValue={kanwilSelected}
|
||||
value={kanwilSelected} |
||||
isClearable={false} |
||||
options={kanwil} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih KPP"> |
||||
KPP |
||||
</Label> |
||||
<Select |
||||
placeholder="Pilih KPP" |
||||
className="basic-single w-100" |
||||
onChange={(e) => { |
||||
setKppSelected(e) |
||||
}} |
||||
classNamePrefix="select" |
||||
// defaultValue={kanwilSelected}
|
||||
value={kppSelected} |
||||
isClearable={false} |
||||
options={kpp} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih Seksi"> |
||||
Seksi |
||||
</Label> |
||||
<MultiSelect |
||||
className="me-1 w-full" |
||||
hasSelectAll={true} |
||||
debounceDuration={300} |
||||
options={seksi} |
||||
value={seksiSelected} |
||||
onChange={(e) => { |
||||
setSeksiSelected(e) |
||||
}} |
||||
labelledBy="Pilih Seksi" |
||||
overrideStrings={{ allItemsAreSelected: 'Semua dipilih', selectSomeItems: 'Pilih Seksi' }} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih AR"> |
||||
AR |
||||
</Label> |
||||
<MultiSelect |
||||
className="me-1 w-full" |
||||
hasSelectAll={true} |
||||
debounceDuration={300} |
||||
options={ar} |
||||
value={arSelected} |
||||
onChange={(e) => { |
||||
setArSelected(e) |
||||
}} |
||||
labelledBy="Pilih AR" |
||||
overrideStrings={{ allItemsAreSelected: 'Semua dipilih', selectSomeItems: 'Pilih AR' }} |
||||
/> |
||||
</Col> |
||||
</Row> |
||||
<Row className="mt-2"> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih Zona"> |
||||
Zona Pengawasan |
||||
</Label> |
||||
<MultiSelect |
||||
className="me-1 w-full" |
||||
hasSelectAll={true} |
||||
debounceDuration={300} |
||||
options={zp} |
||||
value={zpSelected} |
||||
onChange={(e) => { |
||||
setZpSelected(e) |
||||
}} |
||||
labelledBy="Pilih Zona" |
||||
overrideStrings={{ allItemsAreSelected: 'Semua dipilih', selectSomeItems: 'Pilih Zona' }} |
||||
/> |
||||
</Col> |
||||
<Col md="3" className="pt-4"> |
||||
<ButtonP onClick={() => buttonProsesOnClick()} label="Proses" severity="" rounded className="w-10rem text-white text-base" /> |
||||
</Col> |
||||
</Row> |
||||
</TabPane> |
||||
<TabPane tabId="perekam"> |
||||
<NipPerekam |
||||
dataSend={dataSend} |
||||
setDataSend={setDataSend} |
||||
activeTab={active} |
||||
toast={toast} |
||||
setHiddenGraphMatoa={setHiddenGraphMatoa} |
||||
dataOpsi={dataOpsi} |
||||
/> |
||||
</TabPane> |
||||
<TabPane tabId="pengampu"> |
||||
<NipPengampu |
||||
dataSend={dataSend} |
||||
setDataSend={setDataSend} |
||||
activeTab={active} |
||||
toast={toast} |
||||
setHiddenGraphMatoa={setHiddenGraphMatoa} |
||||
dataOpsi={dataOpsi} |
||||
/> |
||||
</TabPane> |
||||
</TabContent> |
||||
</CardBody> |
||||
</Card> |
||||
</Col> |
||||
</Row> |
||||
|
||||
<Row hidden={['pengampu', 'perekam'].includes(storeKpdl.selectedOpsi?.name)}> |
||||
<Col sm="12"> |
||||
<Card> |
||||
<CardHeader className="d-flex justify-content-center p-2"> |
||||
<CardTitle tag={'h1'} className="font-weight-bold"> |
||||
Statistik Penguasaan Wilayah |
||||
</CardTitle> |
||||
</CardHeader> |
||||
<CardBody className="p-1"> |
||||
<div id="graph_matoa_agg"> |
||||
<HighchartsReact ref={refChart1} highcharts={Highcharts} options={optionsGraphMatoaAgg} /> |
||||
</div> |
||||
</CardBody> |
||||
</Card> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col sm="12"> |
||||
<Card> |
||||
<CardHeader className="d-flex justify-content-center p-2"> |
||||
<CardTitle tag={'h1'} className="font-weight-bold"> |
||||
Statistik Progresifitas & Sebaran Data Hasil Kegiatan Matoa |
||||
</CardTitle> |
||||
</CardHeader> |
||||
<CardBody> |
||||
<TabProgresifitas dataSend={dataSend} /> |
||||
</CardBody> |
||||
</Card> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col sm="12"> |
||||
<TabPenugasan dataSend={dataSend} /> |
||||
</Col> |
||||
</Row> |
||||
<Toast ref={toast} /> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
const container = document.getElementById('app') |
||||
const component = ( |
||||
<Provider store={store}> |
||||
<Root /> |
||||
</Provider> |
||||
) |
||||
|
||||
ReactDOM.render(component, container) |
@ -1,27 +0,0 @@
|
||||
<link rel="stylesheet" href="<?=base_url('public/kpdl/dist/kpdl.css')?>">
|
||||
<style> |
||||
.highcharts-credits{ |
||||
visibility: hidden; |
||||
} |
||||
</style> |
||||
<?php |
||||
helper('Kpdl'); |
||||
?> |
||||
|
||||
<div class="main-content"> |
||||
<div class="container-fluid"> |
||||
<div id="app"></div> |
||||
|
||||
</div> |
||||
</div> |
||||
|
||||
|
||||
|
||||
<?php $isDevelopment = ENVIRONMENT === 'development';?> |
||||
|
||||
<script type="text/javascript"> |
||||
|
||||
<?php echo view('kewilayahan/dist/kpdl.js') ?> |
||||
</script> |
||||
|
||||
<?php echo view('inc/js.php') ?> |
@ -1,24 +0,0 @@
|
||||
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit' |
||||
export const kpdlSlice = createSlice({ |
||||
name: 'kpdl', |
||||
initialState: { |
||||
selectedOpsi: null, |
||||
dataMonitoring: [], |
||||
dataUrut: { urutKanwil: [], urutKpp: [], urutSeksi: [], urutPegawai: [] } |
||||
}, |
||||
reducers: { |
||||
setSelectedOpsi: (state, action) => { |
||||
state.selectedOpsi = action.payload |
||||
}, |
||||
setDataMonitoring: (state, action) => { |
||||
state.dataMonitoring = action.payload |
||||
}, |
||||
setDataUrut: (state, action) => { |
||||
state.dataUrut = action.payload |
||||
} |
||||
} |
||||
}) |
||||
|
||||
export const { setSelectedOpsi, setDataMonitoring, setDataUrut } = kpdlSlice.actions |
||||
|
||||
export default kpdlSlice.reducer |
@ -1,15 +0,0 @@
|
||||
import { configureStore } from "@reduxjs/toolkit" |
||||
import kpdl from "./KpdlStore" |
||||
const rootReducer = { |
||||
kpdl |
||||
} |
||||
const store = configureStore({ |
||||
reducer: rootReducer, |
||||
middleware: (getDefaultMiddleware) => { |
||||
return getDefaultMiddleware({ |
||||
serializableCheck: false |
||||
}) |
||||
} |
||||
}) |
||||
|
||||
export { store } |
@ -1,16 +0,0 @@
|
||||
export const isObjEmpty = (obj) => Object.keys(obj).length === 0 |
||||
export function format_angka(num) { |
||||
var num_parts = num.toString().split('.') |
||||
num_parts[0] = num_parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, '.') |
||||
return num_parts.join(',') |
||||
} |
||||
export function titleCase(str) { |
||||
var splitStr = str.toLowerCase().split(' ') |
||||
for (var i = 0; i < splitStr.length; i++) { |
||||
// You do not need to check if i is larger than splitStr length, as your for does that for you
|
||||
// Assign it back to the array
|
||||
splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1) |
||||
} |
||||
// Directly return the joined string
|
||||
return splitStr.join(' ') |
||||
} |
@ -1,255 +0,0 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Card, CardBody, CardHeader, CardTitle, Col, Label, Row } from 'reactstrap' |
||||
import collect from 'collect.js' |
||||
import { Toast } from 'primereact/toast' |
||||
import 'primereact/resources/themes/bootstrap4-light-blue/theme.css' |
||||
import 'primeflex/primeflex.css' |
||||
import { MantineReactTable } from 'mantine-react-table' |
||||
import $ from 'jquery' |
||||
import { isObjEmpty, titleCase } from '../../kytp/util' |
||||
import { useSelector } from 'react-redux' |
||||
const date = new Date() |
||||
|
||||
const Kanwil = () => { |
||||
const base_url = '<?=base_url()?>' |
||||
const toast = useRef(null) |
||||
|
||||
const refChart1 = useRef() |
||||
const refChart2 = useRef() |
||||
const refChart3 = useRef() |
||||
// const refChart4 = useRef()
|
||||
|
||||
const [data, setData] = useState([]) |
||||
|
||||
const [urutKanwil, setUrutKanwil] = useState({ categories: [], dataSeries: [] }) |
||||
const [urutKpp, setUrutKpp] = useState({ categories: [], dataSeries: [] }) |
||||
const [urutSeksi, setUrutSeksi] = useState({ categories: [], dataSeries: [] }) |
||||
const [urutPegawai, setUrutPegawai] = useState({ categories: [], dataSeries: [] }) |
||||
const storeKpdl = useSelector((state) => state.kpdl) |
||||
|
||||
useEffect(() => { |
||||
// if (isObjEmpty(paramSelected)) {
|
||||
// return
|
||||
// }
|
||||
// const kanwil = collect(kanwilSelected).pluck('value').all()
|
||||
// const kpp = collect(kppSelected).pluck('value').all()
|
||||
const data = storeKpdl.dataUrut |
||||
|
||||
setUrutKanwil(() => { |
||||
const categories = [] |
||||
const dataSeries = [] |
||||
data.urutKanwil.map((val, idx) => { |
||||
categories.push(String(val.LABEL).replace('Kanwil DJP', '')) |
||||
dataSeries.push(val.RATA_RATA) |
||||
}) |
||||
return { categories, dataSeries } |
||||
}) |
||||
setUrutKpp(() => { |
||||
const categories = [] |
||||
const dataSeries = [] |
||||
data.urutKpp.map((val, idx) => { |
||||
categories.push(String(val.LABEL).replace('KPP Pratama', '')) |
||||
dataSeries.push(val.RATA_RATA) |
||||
}) |
||||
return { categories, dataSeries } |
||||
}) |
||||
setUrutSeksi(() => { |
||||
const categories = [] |
||||
const dataSeries = [] |
||||
data.urutSeksi.map((val, idx) => { |
||||
categories.push(String(val.LABEL).replace('Seksi', '') + '-' + String(val.NAMA_KANTOR).replace('KPP Pratama', '')) |
||||
dataSeries.push(val.RATA_RATA) |
||||
}) |
||||
return { categories, dataSeries } |
||||
}) |
||||
setUrutPegawai(() => { |
||||
const categories = [] |
||||
const dataSeries = [] |
||||
data.urutPegawai.map((val, idx) => { |
||||
categories.push(String(val.LABEL) + ' - ' + String(val.NAMA_UNIT_ES4).replace('Seksi', '') + ' - ' + String(val.NAMA_KANTOR).replace('KPP Pratama', '')) |
||||
dataSeries.push(val.JUMLAH) |
||||
}) |
||||
return { categories, dataSeries } |
||||
}) |
||||
}, [storeKpdl.dataMonitoring, storeKpdl.dataUrut]) |
||||
|
||||
const columns = useMemo( |
||||
() => [ |
||||
{ |
||||
accessorKey: 'LABEL', |
||||
header: 'Unit/Pegawai', |
||||
size: 200, |
||||
mantineTableBodyCellProps: ({ cell }) => { |
||||
const rowObject = cell.row.original |
||||
if (!cell.row.getCanExpand()) { |
||||
if (rowObject.ISEXIST_INWAS === 'FALSE') { |
||||
return { style: { color: 'red' } } |
||||
} |
||||
if (rowObject.NAMA_JABATAN === 'Kepala Seksi') { |
||||
return { style: { color: 'blue' } } |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH', |
||||
header: 'Jml. Subjek', |
||||
size: 80, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
Cell: ({ cell }) => Number(cell.getValue()).toLocaleString('id-ID') |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH_AR', |
||||
header: 'AR Existing', |
||||
size: 80, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
Cell: ({ cell }) => Number(cell.getValue()).toLocaleString('id-ID') |
||||
}, |
||||
{ |
||||
accessorKey: 'RATA_RATA', |
||||
header: 'Rata-rata Per AR', |
||||
size: 80, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
Cell: ({ cell }) => Number(cell.getValue()).toLocaleString('id-ID', { maximumFractionDigits: 2 }), |
||||
sortDescFirst: true |
||||
} |
||||
], |
||||
[] |
||||
) |
||||
|
||||
const optionsChart = (props, title, urutChart) => { |
||||
return { |
||||
chart: { |
||||
type: 'bar', |
||||
height: 350, |
||||
borderColor: '#EBBA95', |
||||
borderWidth: 2 |
||||
}, |
||||
title: { |
||||
text: `${title}`, |
||||
style: { fontSize: '14px' }, |
||||
useHTML: true |
||||
}, |
||||
|
||||
xAxis: { |
||||
categories: props.categories, |
||||
labels: { |
||||
formatter: function () { |
||||
return urutChart === 4 ? String(this.value).split('-')[0] : this.value |
||||
}, |
||||
allowOverlap: false, |
||||
style: { |
||||
whiteSpace: 'wrap', |
||||
overflow: 'allow' |
||||
} |
||||
} |
||||
}, |
||||
yAxis: { |
||||
min: 0, |
||||
title: { |
||||
text: null |
||||
}, |
||||
labels: { |
||||
overflow: 'justify' |
||||
}, |
||||
gridLineWidth: 0 |
||||
}, |
||||
tooltip: { |
||||
valueSuffix: ' Subjek', |
||||
backgroundColor: '#FCFFC5', |
||||
// pointFormat: '{point.y}',
|
||||
formatter: function () { |
||||
return '<b>' + this.x + '</b> : <b>' + Number(this.y).toLocaleString('id-ID', { maximumFractionDigits: 2 }) + '</b>' |
||||
}, |
||||
enabled: true |
||||
}, |
||||
plotOptions: { |
||||
bar: { |
||||
borderRadius: '20%', |
||||
dataLabels: { |
||||
enabled: true, |
||||
formatter: function () { |
||||
return `${Number(this.y).toLocaleString('id-ID', { |
||||
minimumFractionDigits: 0, |
||||
maximumFractionDigits: 2 |
||||
})}` |
||||
} |
||||
}, |
||||
groupPadding: 0.1 |
||||
} |
||||
}, |
||||
credits: { |
||||
enabled: false |
||||
}, |
||||
series: [{ name: 'Subjek KPDL', data: props.dataSeries }] |
||||
} |
||||
} |
||||
return ( |
||||
<> |
||||
<Row style={{ minHeight: '200px' }}> |
||||
<Col md="8"> |
||||
<MantineReactTable |
||||
initialState={{ sorting: [{ id: 'RATA_RATA', desc: true }] }} |
||||
columns={columns} |
||||
data={storeKpdl.dataMonitoring} |
||||
enableExpanding |
||||
enableExpandAll //default
|
||||
mantineTopToolbarProps={{ className: 'z-0', allowFullScreen: false }} |
||||
enableFullScreenToggle={false} |
||||
enablePagination={false} |
||||
mantineTableBodyCellProps={({ cell }) => ({ |
||||
className: 'text-xs py-1', |
||||
sx: { |
||||
backgroundColor: cell.row.depth === 1 || !cell.row.getCanExpand() ? 'ButtonHighlight' : 'inherit', |
||||
fontWeight: cell.row.depth === 0 ? '600' : 'inherit' |
||||
} |
||||
})} |
||||
mantineTableBodyProps={{ className: 'mb-3' }} |
||||
mantineTableHeadCellProps={{ align: 'center', className: 'text-xs p-1' }} |
||||
enableTableFooter |
||||
renderBottomToolbar={false} |
||||
mantineTableProps={{ |
||||
highlightOnHover: false, |
||||
withColumnBorders: true |
||||
}} |
||||
content |
||||
/> |
||||
</Col> |
||||
<Col md="4"> |
||||
<Row> |
||||
{urutKanwil.dataSeries.length ? ( |
||||
<Col md="12" className="m-1"> |
||||
<HighchartsReact ref={refChart1} highcharts={Highcharts} options={optionsChart(urutKanwil, 'Urut Rata-rata Kanwil', 1)} /> |
||||
</Col> |
||||
) : null} |
||||
{urutKpp.dataSeries.length ? ( |
||||
<Col md="12" className="m-1"> |
||||
<HighchartsReact ref={refChart2} highcharts={Highcharts} options={optionsChart(urutKpp, 'Urut Rata-rata KPP', 2)} /> |
||||
</Col> |
||||
) : null} |
||||
{urutKpp.dataSeries.length ? ( |
||||
<Col md="12" className="m-1"> |
||||
<HighchartsReact ref={refChart3} highcharts={Highcharts} options={optionsChart(urutSeksi, 'Urut Rata-rata Seksi', 3)} /> |
||||
</Col> |
||||
) : null} |
||||
{urutKpp.dataSeries.length ? ( |
||||
<Col md="12" className="m-1"> |
||||
<HighchartsReact ref={refChart3} highcharts={Highcharts} options={optionsChart(urutPegawai, 'Jml. Subjek Urut AR', 4)} /> |
||||
</Col> |
||||
) : null} |
||||
</Row> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default Kanwil |
@ -1,138 +0,0 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Card, CardBody, CardHeader, CardTitle, Col, Label, Row } from 'reactstrap' |
||||
import collect from 'collect.js' |
||||
import { Toast } from 'primereact/toast' |
||||
import 'primereact/resources/themes/bootstrap4-light-blue/theme.css' |
||||
import 'primeflex/primeflex.css' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import $ from 'jquery' |
||||
import { isObjEmpty, titleCase } from '../../kytp/util' |
||||
import { useSelector } from 'react-redux' |
||||
const date = new Date() |
||||
|
||||
const Kpp = () => { |
||||
const base_url = '<?=base_url()?>' |
||||
const toast = useRef(null) |
||||
const [isLoading, setIsLoading] = useState() |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
|
||||
const [data, setData] = useState([]) |
||||
const [sorting, setSorting] = useState([{ id: 'RATA_RATA', desc: true }]) |
||||
|
||||
const storeKpdl = useSelector((state) => state.kpdl) |
||||
useEffect(() => { |
||||
if (data.length) { |
||||
try { |
||||
//scroll to the top of the table when the sorting changes
|
||||
rowVirtualizerInstanceRef.current?.scrollToIndex(0) |
||||
} catch (e) { |
||||
// console.log(e)
|
||||
} |
||||
} |
||||
}, [sorting]) |
||||
|
||||
useEffect(() => { |
||||
const sharedData = storeKpdl.dataMonitoring |
||||
const data = [] |
||||
sharedData.map((val, _idx) => { |
||||
val.subRows.map((val2, _idx2) => { |
||||
data.push(val2) |
||||
}) |
||||
}) |
||||
setData(data) |
||||
setIsLoading(false) |
||||
}, [storeKpdl.dataMonitoring]) |
||||
|
||||
const columns = useMemo( |
||||
() => [ |
||||
{ |
||||
accessorKey: 'LABEL', |
||||
header: 'Unit/Pegawai', |
||||
size: 200, |
||||
mantineTableBodyCellProps: ({ cell }) => { |
||||
const rowObject = cell.row.original |
||||
if (!cell.row.getCanExpand()) { |
||||
if (rowObject.ISEXIST_INWAS === 'FALSE') { |
||||
return { style: { color: 'red' } } |
||||
} |
||||
if (rowObject.NAMA_JABATAN === 'Kepala Seksi') { |
||||
return { style: { color: 'blue' } } |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH', |
||||
header: 'Jml. Subjek', |
||||
size: 80, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
Cell: ({ cell }) => Number(cell.getValue()).toLocaleString('id-ID') |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH_AR', |
||||
header: 'AR Existing', |
||||
size: 80, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
Cell: ({ cell }) => Number(cell.getValue()).toLocaleString('id-ID') |
||||
}, |
||||
{ |
||||
accessorKey: 'RATA_RATA', |
||||
header: 'Rata-rata Per AR', |
||||
size: 80, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
Cell: ({ cell }) => Number(cell.getValue()).toLocaleString('id-ID', { maximumFractionDigits: 2 }) |
||||
} |
||||
], |
||||
[] |
||||
) |
||||
const table = useMantineReactTable({ |
||||
columns, |
||||
data, //10,000 rows
|
||||
enableBottomToolbar: false, |
||||
enableGlobalFilterModes: true, |
||||
enablePagination: false, |
||||
enableRowVirtualization: true, |
||||
mantineTableContainerProps: { sx: { maxHeight: '600px' }, className: 'p-2' }, |
||||
onSortingChange: setSorting, |
||||
state: { isLoading, sorting }, |
||||
rowVirtualizerProps: { overscan: 8 }, //optionally customize the virtualizer
|
||||
enableExpanding: true, |
||||
mantineTopToolbarProps: { allowFullScreen: false }, |
||||
enableFullScreenToggle: false, |
||||
enablePagination: false, |
||||
mantineTableBodyCellProps: ({ cell }) => ({ |
||||
className: 'text-xs py-1', |
||||
sx: { |
||||
backgroundColor: cell.row.depth === 1 ? 'ButtonHighlight' : 'inherit', |
||||
fontWeight: cell.row.depth === 0 ? '600' : 'inherit' |
||||
} |
||||
}), |
||||
mantineTableBodyProps: { className: 'mb-3' }, |
||||
mantineTableHeadCellProps: { align: 'center', className: 'text-xs p-1' }, |
||||
renderBottomToolbar: false, |
||||
mantineTableProps: { |
||||
highlightOnHover: false, |
||||
withColumnBorders: true |
||||
}, |
||||
rowVirtualizerInstanceRef |
||||
}) |
||||
return ( |
||||
<> |
||||
<Row style={{ minHeight: '200px' }}> |
||||
<Col> |
||||
<MantineReactTable table={table} /> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default Kpp |
@ -1,134 +0,0 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Card, CardBody, CardHeader, CardTitle, Col, Label, Row } from 'reactstrap' |
||||
import collect from 'collect.js' |
||||
import { Toast } from 'primereact/toast' |
||||
import 'primereact/resources/themes/bootstrap4-light-blue/theme.css' |
||||
import 'primeflex/primeflex.css' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import $ from 'jquery' |
||||
import { isObjEmpty, titleCase } from '../../kytp/util' |
||||
import { useSelector } from 'react-redux' |
||||
const date = new Date() |
||||
|
||||
const Pegawai = () => { |
||||
const base_url = '<?=base_url()?>' |
||||
const toast = useRef(null) |
||||
|
||||
const refChart1 = useRef() |
||||
const refChart2 = useRef() |
||||
const refChart3 = useRef() |
||||
// const refChart4 = useRef()
|
||||
|
||||
const [data, setData] = useState([]) |
||||
const [isLoading, setIsLoading] = useState() |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
const [sorting, setSorting] = useState([{ id: 'JUMLAH', desc: true }]) |
||||
const storeKpdl = useSelector((state) => state.kpdl) |
||||
useEffect(() => { |
||||
try { |
||||
//scroll to the top of the table when the sorting changes
|
||||
rowVirtualizerInstanceRef.current?.scrollToIndex(0) |
||||
} catch (e) { |
||||
// console.log(e)
|
||||
} |
||||
}, [sorting]) |
||||
|
||||
useEffect(() => { |
||||
const sharedData = storeKpdl.dataMonitoring |
||||
const data = [] |
||||
sharedData.map((val, _idx) => { |
||||
val.subRows.map((val2, _idx2) => { |
||||
val2.subRows.map((val3, _idx3) => { |
||||
data.push(...val3.subRows) |
||||
}) |
||||
}) |
||||
}) |
||||
setData(data) |
||||
setIsLoading(false) |
||||
}, [storeKpdl.dataMonitoring]) |
||||
|
||||
const columns = useMemo( |
||||
() => [ |
||||
{ |
||||
accessorKey: 'LABEL', |
||||
header: 'Unit/Pegawai', |
||||
size: 200, |
||||
Cell: ({ cell }) => { |
||||
const rowData = cell.row.original |
||||
return cell.getValue() + ' - ' + rowData.NAMA_KANTOR + ' - ' + rowData.NAMA_UNIT_ES4 |
||||
}, |
||||
mantineTableBodyCellProps: ({ cell }) => { |
||||
const rowObject = cell.row.original |
||||
if (!cell.row.getCanExpand()) { |
||||
if (rowObject.ISEXIST_INWAS === 'FALSE') { |
||||
return { style: { color: 'red' } } |
||||
} |
||||
if (rowObject.NAMA_JABATAN === 'Kepala Seksi') { |
||||
return { style: { color: 'blue' } } |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH', |
||||
header: 'Jml. Subjek', |
||||
size: 80, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
Cell: ({ cell }) => Number(cell.getValue()).toLocaleString('id-ID') |
||||
} |
||||
], |
||||
[] |
||||
) |
||||
const table = useMantineReactTable({ |
||||
columns, |
||||
data, //10,000 rows
|
||||
enableBottomToolbar: false, |
||||
enableGlobalFilterModes: true, |
||||
enableRowVirtualization: true, |
||||
mantineTableContainerProps: { sx: { maxHeight: '600px' } }, |
||||
onSortingChange: setSorting, |
||||
state: { isLoading, sorting }, |
||||
rowVirtualizerProps: { overscan: 8 }, //optionally customize the virtualizer
|
||||
mantineTopToolbarProps: { allowFullScreen: false }, |
||||
enableFullScreenToggle: false, |
||||
enablePagination: false, |
||||
mantineTableBodyCellProps: ({ cell }) => ({ |
||||
className: 'text-xs py-1', |
||||
sx: { |
||||
fontWeight: cell.row.depth === 0 ? '600' : 'inherit' |
||||
} |
||||
}), |
||||
mantineTableBodyProps: { className: 'mb-3' }, |
||||
mantineTableHeadCellProps: { align: 'center', className: 'text-xs p-1' }, |
||||
renderBottomToolbar: false, |
||||
mantineTableProps: { |
||||
highlightOnHover: false, |
||||
withColumnBorders: true |
||||
}, |
||||
rowVirtualizerInstanceRef, |
||||
enableRowNumbers: true, |
||||
displayColumnDefOptions: { |
||||
'mrt-row-numbers': { |
||||
mantineTableBodyCellProps: { |
||||
align: 'center' |
||||
}, |
||||
size: 80 |
||||
} |
||||
} |
||||
}) |
||||
return ( |
||||
<> |
||||
<Row style={{ minHeight: '200px' }}> |
||||
<Col> |
||||
<MantineReactTable table={table} /> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default Pegawai |
@ -1,145 +0,0 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react' |
||||
import Highcharts from 'highcharts' |
||||
import HighchartsReact from 'highcharts-react-official' |
||||
import { Card, CardBody, CardHeader, CardTitle, Col, Label, Row } from 'reactstrap' |
||||
import collect from 'collect.js' |
||||
import { Toast } from 'primereact/toast' |
||||
import 'primereact/resources/themes/bootstrap4-light-blue/theme.css' |
||||
import 'primeflex/primeflex.css' |
||||
import { MantineReactTable, useMantineReactTable } from 'mantine-react-table' |
||||
import $ from 'jquery' |
||||
import { isObjEmpty, titleCase } from '../../kytp/util' |
||||
import { useSelector } from 'react-redux' |
||||
const date = new Date() |
||||
|
||||
const Seksi = () => { |
||||
const base_url = '<?=base_url()?>' |
||||
const toast = useRef(null) |
||||
|
||||
const refChart1 = useRef() |
||||
const refChart2 = useRef() |
||||
const refChart3 = useRef() |
||||
// const refChart4 = useRef()
|
||||
|
||||
const [data, setData] = useState([]) |
||||
const [isLoading, setIsLoading] = useState() |
||||
const rowVirtualizerInstanceRef = useRef(null) |
||||
const [sorting, setSorting] = useState([{ id: 'RATA_RATA', desc: true }]) |
||||
const storeKpdl = useSelector((state) => state.kpdl) |
||||
useEffect(() => { |
||||
try { |
||||
//scroll to the top of the table when the sorting changes
|
||||
rowVirtualizerInstanceRef.current?.scrollToIndex(0) |
||||
} catch (e) { |
||||
console.log(e) |
||||
} |
||||
}, [sorting]) |
||||
|
||||
useEffect(() => { |
||||
const sharedData = storeKpdl.dataMonitoring |
||||
const data = [] |
||||
sharedData.map((val, _idx) => { |
||||
val.subRows.map((val2, _idx2) => { |
||||
val2.subRows.map((val3, _idx3) => { |
||||
data.push(val3) |
||||
}) |
||||
}) |
||||
}) |
||||
setData(data) |
||||
setIsLoading(false) |
||||
}, [storeKpdl.dataMonitoring]) |
||||
|
||||
const columns = useMemo( |
||||
() => [ |
||||
{ |
||||
accessorKey: 'LABEL', |
||||
header: 'Unit/Pegawai', |
||||
size: 200, |
||||
Cell: ({ cell }) => { |
||||
const rowData = cell.row.original |
||||
return cell.getValue() + ' - ' + rowData.NAMA_KANTOR |
||||
}, |
||||
mantineTableBodyCellProps: ({ cell }) => { |
||||
const rowObject = cell.row.original |
||||
if (!cell.row.getCanExpand()) { |
||||
if (rowObject.ISEXIST_INWAS === 'FALSE') { |
||||
return { style: { color: 'red' } } |
||||
} |
||||
if (rowObject.NAMA_JABATAN === 'Kepala Seksi') { |
||||
return { style: { color: 'blue' } } |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH', |
||||
header: 'Jml. Subjek', |
||||
size: 80, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
Cell: ({ cell }) => Number(cell.getValue()).toLocaleString('id-ID') |
||||
}, |
||||
{ |
||||
accessorKey: 'JUMLAH_AR', |
||||
header: 'AR Existing', |
||||
size: 80, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
Cell: ({ cell }) => Number(cell.getValue()).toLocaleString('id-ID') |
||||
}, |
||||
{ |
||||
accessorKey: 'RATA_RATA', |
||||
header: 'Rata-rata Per AR', |
||||
size: 80, |
||||
mantineTableBodyCellProps: { |
||||
align: 'right' |
||||
}, |
||||
Cell: ({ cell }) => Number(cell.getValue()).toLocaleString('id-ID', { maximumFractionDigits: 2 }) |
||||
} |
||||
], |
||||
[] |
||||
) |
||||
const table = useMantineReactTable({ |
||||
columns, |
||||
data, //10,000 rows
|
||||
enableBottomToolbar: false, |
||||
enableGlobalFilterModes: true, |
||||
enableRowVirtualization: true, |
||||
mantineTableContainerProps: { sx: { maxHeight: '600px' } }, |
||||
onSortingChange: setSorting, |
||||
state: { isLoading, sorting }, |
||||
rowVirtualizerProps: { overscan: 8 }, //optionally customize the virtualizer
|
||||
enableExpanding: true, |
||||
mantineTopToolbarProps: { allowFullScreen: false }, |
||||
enableFullScreenToggle: false, |
||||
enablePagination: false, |
||||
mantineTableBodyCellProps: ({ cell }) => ({ |
||||
className: 'text-xs py-1', |
||||
sx: { |
||||
backgroundColor: cell.row.depth === 1 || !cell.row.getCanExpand() ? 'ButtonHighlight' : 'inherit', |
||||
fontWeight: cell.row.depth === 0 ? '600' : 'inherit' |
||||
} |
||||
}), |
||||
mantineTableBodyProps: { className: 'mb-3' }, |
||||
mantineTableHeadCellProps: { align: 'center', className: 'text-xs p-1' }, |
||||
renderBottomToolbar: false, |
||||
mantineTableProps: { |
||||
highlightOnHover: false, |
||||
withColumnBorders: true |
||||
}, |
||||
rowVirtualizerInstanceRef |
||||
}) |
||||
return ( |
||||
<> |
||||
<Row style={{ minHeight: '200px' }}> |
||||
<Col> |
||||
<MantineReactTable table={table} /> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default Seksi |
@ -1,221 +0,0 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react' |
||||
import ReactDOM from 'react-dom' |
||||
import { store } from '../kytp/store/store' |
||||
import { Provider, useDispatch, useSelector } from 'react-redux' |
||||
import { Card, CardBody, CardFooter, CardHeader, CardSubtitle, CardTitle, Col, Label, Nav, NavItem, NavLink, Row, TabContent, TabPane } from 'reactstrap' |
||||
import collect from 'collect.js' |
||||
import { MultiSelect } from 'react-multi-select-component' |
||||
import { Toast } from 'primereact/toast' |
||||
import { Button as ButtonP } from 'primereact/button' |
||||
import 'primereact/resources/themes/bootstrap4-light-blue/theme.css' |
||||
import 'primeflex/primeflex.css' |
||||
import Tanggal from '../commons/Tanggal' |
||||
import $ from 'jquery' |
||||
import Kanwil from './componentMonitoring/Kanwil' |
||||
import Kpp from './componentMonitoring/Kpp' |
||||
import Seksi from './componentMonitoring/Seksi' |
||||
import { TabPanel, TabView } from 'primereact/tabview' |
||||
import Pegawai from './componentMonitoring/Pegawai' |
||||
import { setDataMonitoring, setDataUrut } from '../kytp/store/KpdlStore' |
||||
import { Skeleton } from 'primereact/skeleton' |
||||
const date = new Date() |
||||
|
||||
const App = () => { |
||||
const base_url = '<?=base_url()?>' |
||||
const toast = useRef(null) |
||||
const [active, setActive] = useState(0) |
||||
const refTab = useRef() |
||||
const toggle = (tab) => { |
||||
setActive(tab) |
||||
} |
||||
const [kanwil, setKanwil] = useState([]) |
||||
const [kanwilSelected, setKanwilSelected] = useState([]) |
||||
const [kpp, setKpp] = useState([]) |
||||
const [kppSelected, setKppSelected] = useState([]) |
||||
const [tanggalAwal, setTanggalAwal] = useState(new Date(date.getFullYear(), 0, 1).toISOString()) |
||||
const [tanggalAkhir, setTanggalAkhir] = useState(date.toISOString()) |
||||
const [paramSelected, setParamSelected] = useState({}) |
||||
const [loading, setLoading] = useState(false) |
||||
const storeKpdl = useSelector((state) => state.kpdl) |
||||
const dispatch = useDispatch() |
||||
|
||||
useEffect(() => { |
||||
$.ajax({ |
||||
url: base_url + 'kewilayahan/ref/kanwil', |
||||
method: 'GET', |
||||
dataType: 'json', |
||||
success: (data) => { |
||||
setKanwil(data) |
||||
} |
||||
}) |
||||
}, []) |
||||
|
||||
useEffect(() => { |
||||
const kanwil = collect(kanwilSelected).pluck('value').all() |
||||
setKppSelected([]) |
||||
setKpp([]) |
||||
|
||||
if (!kanwil.length) { |
||||
return |
||||
} |
||||
$.ajax({ |
||||
url: base_url + 'kewilayahan/ref/kppmultikanwil', |
||||
method: 'POST', |
||||
dataType: 'json', |
||||
data: { |
||||
kanwil |
||||
}, |
||||
success: (data) => { |
||||
setKpp(data) |
||||
} |
||||
}) |
||||
}, [kanwilSelected]) |
||||
|
||||
const buttonProsesOnClick = () => { |
||||
if (!kppSelected.length) { |
||||
return toast.current.show({ severity: 'info', summary: 'Info', detail: 'KPP harus dipilih' }) |
||||
} |
||||
|
||||
if (!tanggalAwal) { |
||||
return toast.current.show({ severity: 'info', summary: 'Info', detail: 'Periode Awal harus dipilih' }) |
||||
} |
||||
if (!tanggalAkhir) { |
||||
return toast.current.show({ severity: 'info', summary: 'Info', detail: 'Periode Akhir harus dipilih' }) |
||||
} |
||||
setActive(0) |
||||
setParamSelected({ |
||||
kanwilSelected, |
||||
kppSelected, |
||||
tanggalAwal, |
||||
tanggalAkhir |
||||
}) |
||||
|
||||
const kanwil = collect(kanwilSelected).pluck('value').all() |
||||
const kpp = collect(kppSelected).pluck('value').all() |
||||
setLoading(true) |
||||
$.ajax({ |
||||
url: base_url + 'kewilayahan/monitoring/data', |
||||
method: 'POST', |
||||
dataType: 'json', |
||||
data: { |
||||
kanwil, |
||||
kpp, |
||||
tanggalAwal, |
||||
tanggalAkhir |
||||
}, |
||||
success: (dataReturn) => { |
||||
dispatch(setDataMonitoring(dataReturn.data)) |
||||
dispatch( |
||||
setDataUrut({ urutKanwil: dataReturn.urutKanwil, urutKpp: dataReturn.urutKpp, urutSeksi: dataReturn.urutSeksi, urutPegawai: dataReturn.urutPegawai }) |
||||
) |
||||
} |
||||
}).done(() => { |
||||
setLoading(false) |
||||
}) |
||||
} |
||||
|
||||
return ( |
||||
<> |
||||
<Card> |
||||
<CardHeader className="pb-1"> |
||||
<CardTitle tag={'h5'}>Pilih Unit Kerja Perekam dan Tanggal Kegiatan</CardTitle> |
||||
</CardHeader> |
||||
<CardBody className="pt-1"> |
||||
<Row className="mt-2"> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih Kanwil"> |
||||
Kanwil |
||||
</Label> |
||||
<MultiSelect |
||||
className="me-1 w-full multi-select" |
||||
hasSelectAll={true} |
||||
debounceDuration={300} |
||||
options={kanwil} |
||||
value={kanwilSelected} |
||||
onChange={(e) => { |
||||
setKanwilSelected(e) |
||||
}} |
||||
labelledBy="Pilih Kanwil" |
||||
overrideStrings={{ allItemsAreSelected: 'Semua dipilih', selectSomeItems: 'Pilih Kanwil' }} |
||||
/> |
||||
</Col> |
||||
<Col md="3"> |
||||
<Label className="form-label" for="Pilih KPP"> |
||||
KPP |
||||
</Label> |
||||
<MultiSelect |
||||
className="me-1 w-full multi-select" |
||||
hasSelectAll={true} |
||||
debounceDuration={300} |
||||
options={kpp} |
||||
value={kppSelected} |
||||
onChange={(e) => { |
||||
setKppSelected(e) |
||||
}} |
||||
labelledBy="Pilih KPP" |
||||
overrideStrings={{ allItemsAreSelected: 'Semua dipilih', selectSomeItems: 'Pilih KPP' }} |
||||
/> |
||||
</Col> |
||||
<Col md="2"> |
||||
<Tanggal setValue={setTanggalAwal} value={tanggalAwal} startOrEnd={'Periode Awal'} /> |
||||
</Col> |
||||
<Col md="2"> |
||||
<Tanggal setValue={setTanggalAkhir} value={tanggalAkhir} startOrEnd={'Periode Akhir'} /> |
||||
</Col> |
||||
<Col md="2" className="pt-4"> |
||||
<ButtonP onClick={() => buttonProsesOnClick()} label="Proses" severity="" rounded className="w-10rem text-white text-base" /> |
||||
</Col> |
||||
</Row> |
||||
</CardBody> |
||||
</Card> |
||||
<Card> |
||||
<CardBody className="pb-1"> |
||||
<CardTitle tag={'h5'}>Monitoring Kegiatan KPDL Seksi Pengawasan</CardTitle> |
||||
<CardSubtitle className="pb-0 mb-0 text-red-400">Sesuai dengan lingkup pilihan pencarian</CardSubtitle> |
||||
</CardBody> |
||||
<CardBody className="pt-1"> |
||||
{loading ? ( |
||||
<Skeleton className="" shape="rectangle" height="17rem" width="100%"></Skeleton> |
||||
) : ( |
||||
<TabView activeIndex={active} scrollable onTabChange={(e) => setActive(e.index)} className="p-0" pt={{ panelContainer: { className: 'p-0' } }}> |
||||
<TabPanel id="tab_1" header="Kanwil" className="p-0"> |
||||
<Kanwil /> |
||||
</TabPanel> |
||||
<TabPanel id="tab_2" header="KPP" className="p-0"> |
||||
<Kpp /> |
||||
</TabPanel> |
||||
<TabPanel id="tab_3" header="Seksi" className="p-0"> |
||||
<Seksi /> |
||||
</TabPanel> |
||||
<TabPanel id="tab_4" header="Pegawai" className="p-0"> |
||||
<Pegawai /> |
||||
</TabPanel> |
||||
</TabView> |
||||
)} |
||||
</CardBody> |
||||
<CardFooter> |
||||
<div> |
||||
<Label>Legenda Tabel :</Label> |
||||
<ul> |
||||
<li style={{ color: 'blue' }}>Kepala Seksi</li> |
||||
<li style={{ color: 'red' }}>Eks Kepala/Anggota Seksi terkait</li> |
||||
</ul> |
||||
</div> |
||||
</CardFooter> |
||||
</Card> |
||||
|
||||
<Row> |
||||
<Toast ref={toast} /> |
||||
</Row> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
const container = document.getElementById('app') |
||||
const component = ( |
||||
<Provider store={store}> |
||||
<App /> |
||||
</Provider> |
||||
) |
||||
|
||||
ReactDOM.render(component, container) |
@ -1,40 +0,0 @@
|
||||
<link rel="stylesheet" href="<?=base_url('public/kpdl/dist/monitoring.css')?>">
|
||||
|
||||
<style> |
||||
.highcharts-credits{ |
||||
visibility: hidden; |
||||
} |
||||
.tanggal { |
||||
min-height: 40px; |
||||
} |
||||
.multi-select { |
||||
.dropdown-content{ |
||||
z-index: 5 !important; |
||||
} |
||||
} |
||||
.mantine-TableHeadCell-Content-Labels { |
||||
padding-left: 0; |
||||
} |
||||
</style> |
||||
|
||||
<?php |
||||
helper('Kpdl'); |
||||
?> |
||||
|
||||
<div class="main-content"> |
||||
<div class="container-fluid"> |
||||
<div id="app"></div> |
||||
|
||||
</div> |
||||
</div> |
||||
|
||||
|
||||
|
||||
<?php $isDevelopment = ENVIRONMENT === 'development';?> |
||||
|
||||
<script type="text/javascript"> |
||||
|
||||
<?php echo view('kewilayahan/dist/monitoring.js') ?> |
||||
</script> |
||||
|
||||
<?php echo view('inc/js.php') ?> |
@ -1,21 +0,0 @@
|
||||
@import "../../kewilayahan/scss/base/bootstrap-extended/include"; // Bootstrap includes |
||||
@import "../../kewilayahan/scss/base/components/include"; // Components includes |
||||
.map-leaflet { |
||||
|
||||
width: 100%; |
||||
height: 100%; |
||||
z-index: 3; |
||||
|
||||
} |
||||
.leaflet-container { |
||||
width: 100%; |
||||
height: calc(100vh); |
||||
font-family: inherit !important; |
||||
|
||||
} |
||||
.leaflet-control-layers-base > label { |
||||
font-size: larger; |
||||
cursor: pointer; |
||||
/* color: $primary; */ |
||||
font-weight: bold; |
||||
} |
@ -1,25 +0,0 @@
|
||||
/* eslint-disable implicit-arrow-linebreak */ |
||||
/* eslint-disable no-unused-vars */ |
||||
import React, { useEffect, useMemo, useRef, useState } from 'react' |
||||
|
||||
import L from 'leaflet' |
||||
import './L.TileLayer.GeneralWMS' |
||||
|
||||
import { createTileLayerComponent, createElementObject, updateGridLayer } from '@react-leaflet/core' |
||||
|
||||
const GeneralWMS = createTileLayerComponent( |
||||
function createBetterWMSLayer({ options, url, layers, ...props }, context) { |
||||
const layer = new L.tileLayer.generalWms(url, { layers, ...props }, context) |
||||
|
||||
return createElementObject(layer, context) |
||||
}, |
||||
(layer, props, prevProps) => { |
||||
updateGridLayer(layer, props, prevProps) |
||||
|
||||
if (props.params !== null && props.params !== prevProps.params) { |
||||
layer.setParams(props.params) |
||||
} |
||||
} |
||||
) |
||||
|
||||
export default GeneralWMS |
@ -1,88 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */ |
||||
// Credits to https://gist.github.com/rclark/6908938
|
||||
|
||||
L.TileLayer.GeneralWMS = L.TileLayer.WMS.extend({ |
||||
onAdd(map) { |
||||
// Triggered when the layer is added to a map.
|
||||
// Register a click listener, then do all the upstream WMS things
|
||||
L.TileLayer.WMS.prototype.onAdd.call(this, map) |
||||
map.on('click', this.getFeatureInfo, this) |
||||
map.on('move', () => console.log(this)) |
||||
console.log(this) |
||||
}, |
||||
onRemove(map) { |
||||
// Triggered when the layer is removed from a map.
|
||||
// Unregister a click listener, then do all the upstream WMS things
|
||||
L.TileLayer.WMS.prototype.onRemove.call(this, map) |
||||
map.off('click', this.getFeatureInfo, this) |
||||
}, |
||||
async getFeatureInfo(evt) { |
||||
// Make an AJAX request to the server and hope for the best
|
||||
const url = this.getFeatureInfoUrl(evt.latlng), |
||||
showResults = L.Util.bind(this.showGetFeatureInfo, this) |
||||
|
||||
await fetch(url) |
||||
.then((response) => response.json()) |
||||
.then((data) => { |
||||
// console.log(data)
|
||||
const err = typeof data === 'object' ? null : data |
||||
const numberReturned = data?.numberReturned |
||||
|
||||
if (numberReturned === 1) { |
||||
// showResults(err, evt.latlng, JSON.stringify(data))
|
||||
showResults(err, evt.latlng, data.features[0].properties) |
||||
// const id_md = data.features[0].properties.i
|
||||
} |
||||
if (numberReturned > 1) { |
||||
showList(err, evt.latlng, data) |
||||
} |
||||
}) |
||||
.catch((err) => { |
||||
// showResults(JSON.stringify(err))
|
||||
}) |
||||
}, |
||||
|
||||
getFeatureInfoUrl(latlng) { |
||||
// return
|
||||
// const map = useMap()
|
||||
// Construct a GetFeatureInfo request URL given a point
|
||||
const point = this._map.latLngToContainerPoint(latlng) |
||||
const size = this._map.getSize() |
||||
|
||||
// https://docs.geoserver.org/latest/en/user/services/wms/reference.html#wms-getfeatureinfo
|
||||
const params = { |
||||
request: 'GetFeatureInfo', |
||||
service: 'WMS', |
||||
crs: 'EPSG:4326', |
||||
styles: this.wmsParams.styles, |
||||
transparent: this.wmsParams.transparent, |
||||
version: this.wmsParams.version, |
||||
format: this.wmsParams.format, |
||||
bbox: this._map.getBounds().toBBoxString(), |
||||
height: size.y, |
||||
// height: this.wmsParams.height,
|
||||
width: size.x, |
||||
// width: this.wmsParams.width,
|
||||
layers: this.wmsParams.layers, |
||||
viewparams: this.wmsParams.viewparams, |
||||
cql_filter: this.wmsParams.cql_filter, |
||||
query_layers: this.wmsParams.layers, |
||||
info_format: 'application/json', |
||||
feature_count: 1 |
||||
} |
||||
|
||||
params[params.version === '1.3.0' ? 'i' : 'x'] = Math.round(point.x) |
||||
params[params.version === '1.3.0' ? 'j' : 'y'] = Math.round(point.y) |
||||
return this._url + L.Util.getParamString(params, this._url, true) |
||||
}, |
||||
|
||||
showGetFeatureInfo(err, latlng, content) { |
||||
if (err) { |
||||
console.log(err) |
||||
} |
||||
} |
||||
}) |
||||
|
||||
L.tileLayer.generalWms = function (url, options) { |
||||
return new L.TileLayer.GeneralWMS(url, options) |
||||
} |
@ -1,89 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */ |
||||
// Credits to https://gist.github.com/rclark/6908938
|
||||
import L from 'leaflet' |
||||
import 'leaflet.vectorgrid' |
||||
// import { getParamString } from 'leaflet/src/core/Util'
|
||||
import { toBounds } from 'leaflet/src/geometry/Bounds' |
||||
// import { TileLayer } from 'leaflet/src/layer/tile/TileLayer'
|
||||
import Pbf from 'pbf' |
||||
import { VectorTile } from 'vector-tile' |
||||
|
||||
L.VectorGrid.VectorPoi = L.VectorGrid.Protobuf.extend({ |
||||
_getVectorTilePromise: function (coords) { |
||||
var data = { |
||||
s: this._getSubdomain(coords), |
||||
x: coords.x, |
||||
y: coords.y, |
||||
z: coords.z |
||||
// z: this._getZoomForUrl() /// TODO: Maybe replicate TileLayer's maxNativeZoom
|
||||
} |
||||
if (this._map && !this._map.options.crs.infinite) { |
||||
var invertedY = this._globalTileRange.max.y - coords.y |
||||
if (this.options.tms) { |
||||
// Should this option be available in Leaflet.VectorGrid?
|
||||
data['y'] = invertedY |
||||
} |
||||
data['-y'] = invertedY |
||||
} |
||||
|
||||
var tileBounds = this._tileCoordsToNwSe(coords), |
||||
// crs = this._crs,
|
||||
crs = this._map.options.crs, |
||||
bounds = toBounds(crs.project(tileBounds[0]), crs.project(tileBounds[1])), |
||||
min = bounds.min, |
||||
max = bounds.max, |
||||
bbox = (this._wmsVersion >= 1.3 && this._crs === EPSG4326 ? [min.y, min.x, max.y, max.x] : [min.x, min.y, max.x, max.y]).join(',') |
||||
// url = TileLayer.prototype.getTileUrl.call(this, coords)
|
||||
|
||||
var tileUrl = this._url + '&bbox=' + bbox |
||||
// var tileUrl = L.Util.template(this._url, L.extend(data, this.options))
|
||||
return fetch(tileUrl, this.options.fetchOptions) |
||||
.then(function (response) { |
||||
if (!response.ok) { |
||||
return { layers: [] } |
||||
} |
||||
|
||||
return response.blob().then(function (blob) { |
||||
// console.log(blob);
|
||||
|
||||
var reader = new FileReader() |
||||
return new Promise(function (resolve) { |
||||
reader.addEventListener('loadend', function () { |
||||
// reader.result contains the contents of blob as a typed array
|
||||
|
||||
// blob.type === 'application/x-protobuf'
|
||||
var pbf = new Pbf(reader.result) |
||||
console.log(pbf) |
||||
return resolve(new VectorTile(pbf)) |
||||
}) |
||||
reader.readAsArrayBuffer(blob) |
||||
}) |
||||
}) |
||||
}) |
||||
.then(function (json) { |
||||
// console.log('Vector tile:', json.layers)
|
||||
// console.log('Vector tile water:', json.layers.water); // Instance of VectorTileLayer
|
||||
|
||||
// Normalize feature getters into actual instanced features
|
||||
for (var layerName in json.layers) { |
||||
var feats = [] |
||||
|
||||
for (var i = 0; i < json.layers[layerName].length; i++) { |
||||
var feat = json.layers[layerName].feature(i) |
||||
feat.geometry = feat.loadGeometry() |
||||
feat.latlng = feat.loadGeometry() |
||||
console.log(feat) |
||||
feats.push(feat) |
||||
} |
||||
|
||||
json.layers[layerName].features = feats |
||||
} |
||||
|
||||
return json |
||||
}) |
||||
} |
||||
}) |
||||
|
||||
L.vectorGrid.vectorpoi = function (url, options) { |
||||
return new L.VectorGrid.VectorPoi(url, options) |
||||
} |
@ -1,238 +0,0 @@
|
||||
import { useEffect, useRef } from 'react' |
||||
import { createTileLayerComponent, updateGridLayer } from '@react-leaflet/core' |
||||
import L from 'leaflet' |
||||
import isObject from 'lodash/isObject' |
||||
import isFunction from 'lodash/isFunction' |
||||
import isString from 'lodash/isString' |
||||
import isEmpty from 'lodash/isEmpty' |
||||
import clone from 'lodash/clone' |
||||
import cloneDeep from 'lodash/cloneDeep' |
||||
import extend from 'lodash/extend' |
||||
import merge from 'lodash/merge' |
||||
import has from 'lodash/has' |
||||
import find from 'lodash/find' |
||||
import 'leaflet.vectorgrid' |
||||
import './L.VectorGrid.VectorPoi' |
||||
export const VectorGridd = createTileLayerComponent( |
||||
function createTileLayer(props, context) { |
||||
const highlight = useRef(null) |
||||
const active = useRef(null) |
||||
const { |
||||
data, |
||||
style, |
||||
hoverStyle, |
||||
activeStyle, |
||||
onClick, |
||||
onMouseover, |
||||
onMouseout, |
||||
onDblclick, |
||||
onContextmenu, |
||||
vectorTileLayerStyles, |
||||
url, |
||||
maxNativeZoom, |
||||
subdomains, |
||||
accessKey, |
||||
accessToken, |
||||
type = 'protobuf', |
||||
interactive = true, |
||||
idField = '', |
||||
...rest |
||||
} = props |
||||
delete rest.leaflet |
||||
|
||||
useEffect(() => { |
||||
const { tooltipClassName = '', tooltip = null, popup = null } = props |
||||
if (tooltip) { |
||||
vectorGrid.bindTooltip( |
||||
(layer) => { |
||||
if (isFunction(tooltip)) { |
||||
return tooltip(layer) |
||||
} else if (isString(tooltip) && has(layer.properties, tooltip)) { |
||||
return String(layer.properties[tooltip]) |
||||
} else if (isString(tooltip)) { |
||||
return tooltip |
||||
} |
||||
return '' |
||||
}, |
||||
{ |
||||
sticky: true, |
||||
direction: 'auto', |
||||
className: tooltipClassName |
||||
} |
||||
) |
||||
} |
||||
if (popup) { |
||||
vectorGrid.bindPopup(popup) |
||||
} |
||||
}, [props.tooltip, props.popup]) |
||||
|
||||
const baseStyle = (properties, zoom) => { |
||||
if (isFunction(style)) { |
||||
return style(properties) |
||||
} else if (isObject(style)) { |
||||
return style |
||||
} |
||||
return { |
||||
weight: 0.5, |
||||
opacity: 1, |
||||
color: '#ccc', |
||||
fillColor: '#390870', |
||||
fillOpacity: 0.6, |
||||
fill: true, |
||||
stroke: true |
||||
} |
||||
} |
||||
|
||||
const _getFeatureId = (feature) => { |
||||
const { idField } = props |
||||
if (isFunction(idField)) { |
||||
return idField(feature) |
||||
} else if (isString(idField)) { |
||||
return feature.properties[idField] |
||||
} |
||||
} |
||||
|
||||
const setFeatureStyle = (id, style) => { |
||||
vectorGrid.setFeatureStyle(id, style) |
||||
} |
||||
|
||||
const resetFeatureStyle = (id) => { |
||||
vectorGrid.resetFeatureStyle(id) |
||||
} |
||||
|
||||
const clearHighlight = (properties) => { |
||||
if (highlight.current) { |
||||
if (highlight.current !== active.current) { |
||||
resetFeatureStyle(highlight.current) |
||||
} else { |
||||
let st |
||||
if (isFunction(activeStyle)) { |
||||
st = activeStyle(properties) |
||||
} else if (isObject(activeStyle)) { |
||||
st = cloneDeep(activeStyle) |
||||
} |
||||
if (!isEmpty(st)) { |
||||
const base = cloneDeep(baseStyle(properties)) |
||||
const activeStyle = extend(base, st) |
||||
setFeatureStyle(active.current, activeStyle) |
||||
} |
||||
} |
||||
} |
||||
highlight.current = null |
||||
} |
||||
|
||||
const clearActive = () => { |
||||
if (active.current) { |
||||
resetFeatureStyle(active.current) |
||||
} |
||||
active.current = null |
||||
} |
||||
|
||||
const getFeature = (featureId) => { |
||||
const { data, idField } = props |
||||
if (isEmpty(data) || isEmpty(data.features)) return {} |
||||
const feature = find(data.features, ({ properties }) => properties[idField] === featureId) |
||||
return cloneDeep(feature) |
||||
} |
||||
|
||||
const _propagateEvent = (eventHandler, e) => { |
||||
if (!isFunction(eventHandler)) return |
||||
const featureId = _getFeatureId(e.layer) |
||||
const feature = getFeature(featureId) |
||||
const event = cloneDeep(e) |
||||
const mergedEvent = merge(event.target, { |
||||
feature |
||||
}) |
||||
eventHandler(event) |
||||
} |
||||
|
||||
let vectorGrid |
||||
if (type === 'slicer') { |
||||
vectorGrid = new L.vectorGrid.slicer(data, { |
||||
interactive: interactive, |
||||
getFeatureId: (feature) => _getFeatureId(feature), |
||||
rendererFactory: L.svg.tile, |
||||
vectorTileLayerStyles: vectorTileLayerStyles || { |
||||
sliced: (properties, zoom) => { |
||||
const bs = baseStyle(properties, zoom) |
||||
bs.fill = true |
||||
bs.stroke = true |
||||
return bs |
||||
} |
||||
}, |
||||
...rest |
||||
}) |
||||
} else { |
||||
vectorGrid = new L.vectorGrid.vectorpoi(url, { |
||||
interactive: interactive, |
||||
key: accessKey, |
||||
token: accessToken, |
||||
vectorTileLayerStyles: vectorTileLayerStyles, |
||||
getFeatureId: (feature) => _getFeatureId(feature), |
||||
rendererFactory: L.svg.tile, |
||||
...rest |
||||
}) |
||||
} |
||||
vectorGrid |
||||
// .on('mouseover', (e) => {
|
||||
// console.log(e)
|
||||
// const { properties } = e.layer
|
||||
// _propagateEvent(onMouseover, e)
|
||||
// let st
|
||||
// const featureId = _getFeatureId(e.layer)
|
||||
// if (isFunction(hoverStyle)) {
|
||||
// st = hoverStyle(properties)
|
||||
// } else if (isObject(hoverStyle)) {
|
||||
// st = cloneDeep(hoverStyle)
|
||||
// }
|
||||
// if (!isEmpty(st) && featureId) {
|
||||
// clearHighlight(properties)
|
||||
// highlight.current = featureId
|
||||
// const base = cloneDeep(baseStyle(properties))
|
||||
// const hoverStyle = extend(base, st)
|
||||
// setFeatureStyle(featureId, hoverStyle)
|
||||
// }
|
||||
// })
|
||||
// .on('mouseout', (e) => {
|
||||
// const { properties } = e.layer
|
||||
// _propagateEvent(onMouseout, e)
|
||||
// clearHighlight(properties)
|
||||
// })
|
||||
// .on('click', (e) => {
|
||||
// const { properties } = e.layer
|
||||
// const featureId = _getFeatureId(e.layer)
|
||||
// _propagateEvent(onClick, e)
|
||||
// let st
|
||||
// if (isFunction(activeStyle)) {
|
||||
// st = activeStyle(properties)
|
||||
// } else if (isObject(activeStyle)) {
|
||||
// st = cloneDeep(activeStyle)
|
||||
// }
|
||||
// if (!isEmpty(st) && featureId) {
|
||||
// clearActive()
|
||||
// active.current = featureId
|
||||
// const base = cloneDeep(baseStyle(properties))
|
||||
// const activeStyle = extend(base, st)
|
||||
// setFeatureStyle(featureId, activeStyle)
|
||||
// }
|
||||
// })
|
||||
// .on('dblclick', (e) => {
|
||||
// _propagateEvent(onDblclick, e)
|
||||
// clearActive()
|
||||
// })
|
||||
.on('contextmenu', (e) => { |
||||
_propagateEvent(onContextmenu, e) |
||||
clearActive() |
||||
}) |
||||
|
||||
return { |
||||
instance: vectorGrid, |
||||
context |
||||
} |
||||
}, |
||||
function upgrade(layer, props, prevprops) { |
||||
return updateGridLayer(layer, props, prevprops) |
||||
} |
||||
) |
||||
|
||||
export default VectorGridd |
@ -1,28 +0,0 @@
|
||||
/* eslint-disable implicit-arrow-linebreak */ |
||||
/* eslint-disable no-unused-vars */ |
||||
import React, { useEffect, useMemo, useRef, useState } from 'react' |
||||
|
||||
import L from 'leaflet' |
||||
import './L.VectorGrid.VectorPoi' |
||||
|
||||
import { createTileLayerComponent, createElementObject, updateGridLayer } from '@react-leaflet/core' |
||||
|
||||
const VectorPoi = createTileLayerComponent( |
||||
function createBetterWMSLayer({ url, options }, context) { |
||||
const layer = new L.vectorGrid.vectorpoi(url, options, context) |
||||
layer.on('click', (e) => { |
||||
const { properties } = e.layer |
||||
console.log(e) |
||||
}) |
||||
return createElementObject(layer, context) |
||||
}, |
||||
(layer, props, prevProps) => { |
||||
updateGridLayer(layer, props, prevProps) |
||||
|
||||
if (props.params !== null && props.params !== prevProps.params) { |
||||
layer.setParams(props.params) |
||||
} |
||||
} |
||||
) |
||||
|
||||
export default VectorPoi |
@ -1,249 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */ |
||||
import React, { useEffect, useMemo, useRef, useState } from 'react' |
||||
import { useLeafletContext } from '@react-leaflet/core' |
||||
import L from 'leaflet' |
||||
import 'leaflet.vectorgrid' |
||||
import '../generalWms/L.VectorGrid.VectorPoi' |
||||
|
||||
function getVectorStyles(layerName, fieldName) { |
||||
const style = {} |
||||
style[layerName] = function (properties, zoom) { |
||||
const p = properties[fieldName] |
||||
return { |
||||
color: p < 0.001 ? 'transparent' : p < 5 ? '#800026' : p < 15 ? '#E31A1C' : p < 30 ? '#FEB24C' : '#00ff00', |
||||
fillOpacity: 0.2, |
||||
// fillOpacity: 1,
|
||||
stroke: true, |
||||
fill: true, |
||||
//opacity: 0.2,
|
||||
weight: 3 |
||||
} |
||||
} |
||||
return style |
||||
} |
||||
|
||||
export const Styles = { |
||||
water: { |
||||
fill: true, |
||||
weight: 1, |
||||
fillColor: '#06cccc', |
||||
color: '#06cccc', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
admin: { |
||||
weight: 1, |
||||
fillColor: 'pink', |
||||
color: 'pink', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
waterway: { |
||||
weight: 1, |
||||
fillColor: '#2375e0', |
||||
color: '#2375e0', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
landcover: { |
||||
fill: true, |
||||
weight: 1, |
||||
fillColor: '#53e033', |
||||
color: '#53e033', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
landuse: { |
||||
fill: true, |
||||
weight: 1, |
||||
fillColor: '#e5b404', |
||||
color: '#e5b404', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
park: { |
||||
fill: true, |
||||
weight: 1, |
||||
fillColor: '#84ea5b', |
||||
color: '#84ea5b', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
boundary: { |
||||
weight: 1, |
||||
fillColor: '#c545d3', |
||||
color: '#c545d3', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
aeroway: { |
||||
weight: 1, |
||||
fillColor: '#51aeb5', |
||||
color: '#51aeb5', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
road: { |
||||
// mapbox & nextzen only
|
||||
weight: 1, |
||||
fillColor: '#f2b648', |
||||
color: '#f2b648', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
tunnel: { |
||||
// mapbox only
|
||||
weight: 0.5, |
||||
fillColor: '#f2b648', |
||||
color: '#f2b648', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
// dashArray: [4, 4]
|
||||
}, |
||||
bridge: { |
||||
// mapbox only
|
||||
weight: 0.5, |
||||
fillColor: '#f2b648', |
||||
color: '#f2b648', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
// dashArray: [4, 4]
|
||||
}, |
||||
transportation: { |
||||
// openmaptiles only
|
||||
weight: 0.5, |
||||
fillColor: '#f2b648', |
||||
color: '#f2b648', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
// dashArray: [4, 4]
|
||||
}, |
||||
transit: { |
||||
// nextzen only
|
||||
weight: 0.5, |
||||
fillColor: '#f2b648', |
||||
color: '#f2b648', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
// dashArray: [4, 4]
|
||||
}, |
||||
building: { |
||||
fill: true, |
||||
weight: 1, |
||||
fillColor: '#2b2b2b', |
||||
color: '#2b2b2b', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
water_name: { |
||||
weight: 1, |
||||
fillColor: '#022c5b', |
||||
color: '#022c5b', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
transportation_name: { |
||||
weight: 1, |
||||
fillColor: '#bc6b38', |
||||
color: '#bc6b38', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
place: { |
||||
weight: 1, |
||||
fillColor: '#f20e93', |
||||
color: '#f20e93', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
housenumber: { |
||||
weight: 1, |
||||
fillColor: '#ef4c8b', |
||||
color: '#ef4c8b', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
poi: { |
||||
weight: 1, |
||||
fillColor: '#3bb50a', |
||||
color: '#3bb50a', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
kpdl_npwp_tidak_valid: { |
||||
weight: 1, |
||||
fillColor: '#3bb50a', |
||||
color: '#3bb50a', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
earth: { |
||||
// nextzen only
|
||||
fill: true, |
||||
weight: 1, |
||||
fillColor: '#c0c0c0', |
||||
color: '#c0c0c0', |
||||
fillOpacity: 0.2, |
||||
opacity: 0.4 |
||||
}, |
||||
|
||||
// Do not symbolize some stuff for mapbox
|
||||
country_label: [], |
||||
marine_label: [], |
||||
state_label: [], |
||||
place_label: [], |
||||
waterway_label: [], |
||||
poi_label: [], |
||||
road_label: [], |
||||
housenum_label: [], |
||||
|
||||
// Do not symbolize some stuff for openmaptiles
|
||||
country_name: [], |
||||
marine_name: [], |
||||
state_name: [], |
||||
place_name: [], |
||||
waterway_name: [], |
||||
poi_name: [], |
||||
road_name: [], |
||||
housenum_name: [] |
||||
} |
||||
|
||||
export const PoiKpdl = () => { |
||||
const context = useLeafletContext() |
||||
const { map } = context |
||||
|
||||
const providerUrl = `http://localhost:8080/geoserver/wms?REQUEST=GetMap
|
||||
&SERVICE=WMS&VERSION=1.1.0&FORMAT=application/vnd.mapbox-vector-tile&STYLES=&TRANSPARENT=true |
||||
&LAYERS=matoa:kpdl_npwp_tidak_valid |
||||
&TILED=false&WIDTH=256&HEIGHT=256&CRS=EPSG:3857` |
||||
|
||||
const vectorGrid = useMemo(() => { |
||||
const options = { |
||||
interactive: true, |
||||
type: 'protobuf', |
||||
vectorTileLayerStyles: { |
||||
kpdl_npwp_tidak_valid: { weight: 1, fillColor: '#f20e93', color: '#f20e93', fillOpacity: 0.2, opacity: 0.4 } |
||||
} |
||||
} |
||||
|
||||
return L.vectorGrid.vectorpoi(providerUrl, options) |
||||
}, [providerUrl, Styles]) |
||||
|
||||
vectorGrid.on('click', function (e) { |
||||
console.log(this) |
||||
console.log('clicked', e) |
||||
}) |
||||
|
||||
vectorGrid.on('mouseover', function (e) { |
||||
console.log('mouseover', e) |
||||
}) |
||||
|
||||
useEffect(() => { |
||||
map.addLayer(vectorGrid) |
||||
return () => { |
||||
map.removeLayer(vectorGrid) |
||||
} |
||||
}, [map, vectorGrid]) |
||||
|
||||
return null |
||||
} |
@ -1,117 +0,0 @@
|
||||
import L from 'leaflet' |
||||
import 'leaflet-bing-layer' |
||||
const tgl = new Date() |
||||
|
||||
const thn = tgl.getFullYear() |
||||
const BING_KEY = 'AuhiCJHlGzhg93IqUH_oCpl_-ZUrIE6SPftlyGYUvr9Amx5nzA-WqGcPquyFZl4L' |
||||
export const bing_ae_opt = { |
||||
attribution: 'Base Map : <a href="https://www.microsoft.com/en-us/maps/product/print-rights">Microsoft Bing</a>', |
||||
bingMapsKey: BING_KEY, |
||||
imagerySet: 'Aerial', |
||||
culture: 'id-ID', |
||||
minZoom: 1, |
||||
maxZoom: 23, |
||||
minNativeZoom: 1, |
||||
maxNativeZoom: 20 |
||||
} |
||||
|
||||
export const bing_r_opt = { |
||||
attribution: 'Base Map : <a href="https://www.microsoft.com/en-us/maps/product/print-rights">Microsoft Bing</a>', |
||||
bingMapsKey: BING_KEY, |
||||
imagerySet: 'Road', |
||||
culture: 'id-ID', |
||||
minZoom: 1, |
||||
maxZoom: 30, |
||||
minNativeZoom: 1, |
||||
maxNativeZoom: 30 |
||||
} |
||||
|
||||
const Road = L.tileLayer('https://mt{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', { |
||||
attribution: `Map data ©${thn} <a href="https://www.google.com/intl/id_id/help/terms_maps/">Google</a>`, |
||||
maxZoom: 30, |
||||
minZoom: 1, |
||||
tileSize: 256, |
||||
zoomOffset: 0, |
||||
noWrap: false, |
||||
subdomains: '0123', |
||||
accessToken: '' |
||||
}) |
||||
|
||||
const Road_Preview = L.tileLayer('https://mt{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', { |
||||
attribution: `Map data ©${thn} <a href="https://www.google.com/intl/id_id/help/terms_maps/">Google</a>`, |
||||
maxZoom: 30, |
||||
minZoom: 1, |
||||
tileSize: 256, |
||||
zoomOffset: 0, |
||||
noWrap: false, |
||||
subdomains: '0123', |
||||
accessToken: '' |
||||
}) |
||||
|
||||
const Satellite = L.tileLayer('https://mt{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', { |
||||
attribution: `Map data ©${thn} <a href="https://www.google.com/intl/id_id/help/terms_maps/">Google</a>`, |
||||
maxZoom: 30, |
||||
minZoom: 1, |
||||
tileSize: 256, |
||||
zoomOffset: 0, |
||||
noWrap: false, |
||||
subdomains: '0123', |
||||
accessToken: '' |
||||
}) |
||||
const Hybrid = L.tileLayer('https://mt{s}.google.com/vt/lyrs=y&x={x}&y={y}&z={z}', { |
||||
attribution: `Map data ©${thn} <a href="https://www.google.com/intl/id_id/help/terms_maps/">Google</a>`, |
||||
maxZoom: 30, |
||||
minZoom: 1, |
||||
tileSize: 256, |
||||
zoomOffset: 0, |
||||
noWrap: false, |
||||
subdomains: '0123', |
||||
accessToken: '' |
||||
}) |
||||
const OSM1 = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { |
||||
maxZoom: 30, |
||||
minZoom: 1, |
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' |
||||
}) |
||||
// export const Bing_ae = L.tileLayer.bing(bing_ae_opt)
|
||||
// export const Bing_r = L.tileLayer.bing(bing_r_opt)
|
||||
|
||||
// export const baseLayers = {
|
||||
// GoogleRoad: Road,
|
||||
// GoogleSatellite: Satellite,
|
||||
// GoogleHybrid: Hybrid,
|
||||
// OpenStreetMap: OSM1,
|
||||
// BingAerial: Bing_ae,
|
||||
// BingRoad: Bing_r
|
||||
// }
|
||||
|
||||
export const layersmaps = [ |
||||
{ |
||||
name: 'Open Street Map', |
||||
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', |
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', |
||||
subdomains: ['a', 'b', 'c'], |
||||
checked: true |
||||
}, |
||||
{ |
||||
name: 'Google Road', |
||||
url: 'https://mt{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', |
||||
attribution: `Map data ©${thn} <a href="https://www.google.com/intl/id_id/help/terms_maps/">Google</a>`, |
||||
subdomains: ['0', '1', '2', '3'], |
||||
checked: false |
||||
}, |
||||
{ |
||||
name: 'Google Satellite', |
||||
url: 'https://mt{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', |
||||
attribution: `Map data ©${thn} <a href="https://www.google.com/intl/id_id/help/terms_maps/">Google</a>`, |
||||
subdomains: ['0', '1', '2', '3'], |
||||
checked: false |
||||
}, |
||||
{ |
||||
name: 'Google Hybrid', |
||||
url: 'https://mt{s}.google.com/vt/lyrs=y&x={x}&y={y}&z={z}', |
||||
attribution: `Map data ©${thn} <a href="https://www.google.com/intl/id_id/help/terms_maps/">Google</a>`, |
||||
subdomains: ['0', '1', '2', '3'], |
||||
checked: false |
||||
} |
||||
] |
@ -1,33 +0,0 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react' |
||||
|
||||
import GeneralWMS from '../generalWms/GeneralWMS' |
||||
|
||||
// url = http://localhost:8080/geoserver/wms?REQUEST=GetMap
|
||||
// &SERVICE=WMS&VERSION=1.3.0&FORMAT=application/vnd.mapbox-vector-tile&STYLES=&TRANSPARENT=true
|
||||
// &LAYERS=matoa:kpdl_npwp_tidak_valid
|
||||
// &TILED=false&WIDTH=256&HEIGHT=256&CRS=EPSG:3857&BBOX=0,-20037508.342789244,20037508.342789244,0
|
||||
const wmsLayer = { |
||||
id: '777', |
||||
url: '/engineN/geoserver/wms', |
||||
layers: 'matoa:kpdl_npwp_tidak_valid', |
||||
props: { |
||||
id: '777', |
||||
url: '/engineN/geoserver/wms', |
||||
layers: 'matoa:kpdl_npwp_tidak_valid', |
||||
version: '1.1.0', |
||||
format: 'application/vnd.mapbox-vector-tile', |
||||
styles: 'point', |
||||
transparent: true, |
||||
tiled: false, |
||||
zIndex: 150, |
||||
// width: 256,
|
||||
// height: 256,
|
||||
uppercase: true, |
||||
// CRS: 'EPSG:3857',
|
||||
// opacity: '0.8',
|
||||
cql_filter: '1=1' |
||||
} |
||||
} |
||||
export const KPdlLayer = ({ poiKpdlRef }) => { |
||||
return <GeneralWMS ref={poiKpdlRef} key={wmsLayer.id} id={wmsLayer.id} url={wmsLayer.url} layers={wmsLayer.layers} {...wmsLayer.props} /> |
||||
} |
@ -1,135 +0,0 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react' |
||||
import ReactDOM from 'react-dom' |
||||
import { LayersControl, MapContainer, TileLayer, useMap } from 'react-leaflet' |
||||
import L, { CRS, Control, Evented, Events, LatLngExpression, Layer, Map } from 'leaflet' |
||||
import { layersmaps } from './layers/baseLayers' |
||||
|
||||
import 'leaflet/dist/Leaflet.css' |
||||
import 'leaflet.locatecontrol' |
||||
import 'leaflet.locatecontrol/dist/L.Control.Locate.css' |
||||
import '../scss/core.scss' |
||||
import './app-maps.scss' |
||||
// import PoiKpdl from './layers/PoiKpdl'
|
||||
// import VectorPoi from './generalWms/VectorPoi'
|
||||
// import VectorGridd from './generalWms/VectorGridd'
|
||||
import { PoiKpdl } from './layers/PoiKpdl' |
||||
const Root = () => { |
||||
// document.body.style.margin = '0'
|
||||
document.body.className = 'm-0 p-0' |
||||
|
||||
const [map, setMap] = useState() |
||||
const [center, setCenter] = useState([-6.1659502, 106.7140899]) |
||||
const [zoom, setZoom] = useState(14) |
||||
const [layCon, setLayCon] = useState() |
||||
const wmsRef = useRef() |
||||
const poiKpdlRef = useRef() |
||||
|
||||
const layers = [] |
||||
const latestBase = localStorage.getItem('latestBase') ?? 'Open Street Map' |
||||
layersmaps.map((val) => { |
||||
if (val.name === latestBase) { |
||||
val.checked = true |
||||
} else { |
||||
val.checked = false |
||||
} |
||||
|
||||
val = { ...val } |
||||
return layers.push(val) |
||||
}) |
||||
|
||||
function baselayerchange(e) { |
||||
// setSelectedBase(e.name)
|
||||
localStorage.setItem('latestBase', e.name) |
||||
} |
||||
|
||||
const whenReady = (e) => { |
||||
const map = e.target |
||||
|
||||
if (map) { |
||||
map.addControl( |
||||
L.control.locate({ |
||||
drawCircle: false, |
||||
position: `bottomright`, |
||||
locateOptions: { |
||||
enableHighAccuracy: true |
||||
} |
||||
}) |
||||
) |
||||
map.addControl(L.control.zoom({ position: 'bottomright' })) |
||||
map.on('baselayerchange', baselayerchange) |
||||
} |
||||
} |
||||
const optVectorKpdl = { |
||||
id: '777', |
||||
url: '/engineN/geoserver/wms?REQUEST=GetMap&SERVICE=WMS&FORMAT=application/vnd.mapbox-vector-tile&CRS=EPSG:3857&STYLES=&TILED=false&TRANSPARENT=true&VERSION=1.3.0&HEIGHT=256&WIDTH=256&LAYERS=matoa:kpdl_npwp_tidak_valid', |
||||
mapParam: { |
||||
url: '/engineN/geoserver/wms', |
||||
LAYERS: 'matoa:kpdl_npwp_tidak_valid', |
||||
VERSION: '1.1.0', |
||||
FORMAT: 'application/vnd.mapbox-vector-tile', |
||||
TRANSPARENT: true, |
||||
TILED: false, |
||||
// zIndex: 150,
|
||||
WIDTH: 256, |
||||
HEIGHT: 256 |
||||
// uppercase: true,
|
||||
// cql_filter: '1=1'
|
||||
}, |
||||
interactive: true, |
||||
type: 'protobuf' |
||||
} |
||||
const displayMap = useMemo( |
||||
() => ( |
||||
<MapContainer |
||||
style={{ minHeight: '400px', minWidth: '380px' }} |
||||
id="map-container" |
||||
className="map-container" |
||||
ref={setMap} |
||||
center={center} |
||||
zoom={zoom} |
||||
scrollWheelZoom={true} |
||||
zoomControl={false} |
||||
whenReady={(e) => { |
||||
whenReady(e) |
||||
}} |
||||
> |
||||
<LayersControl ref={setLayCon} position="topright"> |
||||
{layers.map((val, idx) => ( |
||||
<LayersControl.BaseLayer name={val.name} key={idx} checked={val.checked}> |
||||
<TileLayer attribution={val.attribution} url={val.url} subdomains={val.subdomains} maxZoom={23} /> |
||||
</LayersControl.BaseLayer> |
||||
))} |
||||
<LayersControl.Overlay name={'Poi Google Map'} checked={true}> |
||||
<PoiKpdl ref={poiKpdlRef} /> |
||||
{/* <VectorGridd |
||||
url={optVectorKpdl.url} |
||||
options={optVectorKpdl} |
||||
vectorTileLayerStyles={{ |
||||
kpdl_npwp_tidak_valid: { |
||||
weight: 0, |
||||
fillColor: '#9bc2c4', |
||||
fillOpacity: 1, |
||||
fill: true |
||||
} |
||||
}} |
||||
/> */} |
||||
</LayersControl.Overlay> |
||||
</LayersControl> |
||||
</MapContainer> |
||||
), |
||||
[] |
||||
) |
||||
return ( |
||||
<> |
||||
<div style={{ height: '100vh', width: '100%', padding: '0' }}> |
||||
<div className="map-leaflet" id="map-leaflet"> |
||||
{displayMap} |
||||
</div> |
||||
</div> |
||||
</> |
||||
) |
||||
} |
||||
const container = document.getElementById('app') |
||||
const component = <Root /> |
||||
|
||||
ReactDOM.render(component, container) |
@ -1,27 +0,0 @@
|
||||
<?php |
||||
helper('Kpdl'); |
||||
?> |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8" /> |
||||
<title>eGeoTax</title> |
||||
<link rel="shortcut icon" href="/engineN/public/favicon.ico" /> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1" /> |
||||
<meta name="theme-color" content="#000000" /> |
||||
<link rel="stylesheet" href="<?=base_url('public/kpdl/dist/peta.css')?>" type="text/css">
|
||||
<style> |
||||
.highcharts-credits{ |
||||
visibility: hidden; |
||||
} |
||||
</style> |
||||
|
||||
</head> |
||||
<body> |
||||
|
||||
<div id="app"></div> |
||||
|
||||
<?php $isDevelopment = ENVIRONMENT === 'development';?> |
||||
<script type="text/javascript" src="<?=base_url()?>public/kpdl/dist/peta.js"></script>
|
||||
|
||||
</body> |
||||
</html> |
@ -1,20 +0,0 @@
|
||||
console posisi di root app (EngineN) |
||||
|
||||
requirement : |
||||
- node versi : 20 + |
||||
- yarn latest version |
||||
|
||||
setup awal jalankan perintah : |
||||
- yarn init |
||||
- yarn (akan mendownload node_modules yang diperlukan) |
||||
|
||||
untuk build kode javascript agar bisa di load di browser => |
||||
jalankan perintah : npx webpack |
||||
untuk dev : npx webpack --watch |
||||
|
||||
config ada webapack.config.js |
||||
|
||||
|
||||
dalam membentuk table yang harus diperhatikan adalah tabel zona pengawasan (KPDL_ZP_NAS_DIFF) : |
||||
- pastikan tidak ada polygon yang saling crossing / intersect karena dapat menyebabkan data KPDL terduplikasi atas beberapa zona pengawasan!!!!! |
||||
- untuk itu atas polygon yang intersect harus dinormalisasi terlebih dahulu.!!!! |
@ -1,47 +0,0 @@
|
||||
// ================================================================================================ |
||||
// File Name: bootstrap-extended.scss |
||||
// Description: List of modified Bootstrap files. This is an actual copy of bootstrap.scss |
||||
// excluding files that have not been modified. |
||||
// ---------------------------------------------------------------------------------------------- |
||||
// Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template |
||||
// Author: PIXINVENT |
||||
// Author URL: http://www.themeforest.net/user/pixinvent |
||||
// ================================================================================================ |
||||
|
||||
@import "bootstrap-extended/include"; // Bootstrap includes |
||||
@import "components/include"; // Components includes |
||||
|
||||
// Custom template mixins |
||||
@import "core/mixins/alert"; // Template custom mixins |
||||
|
||||
// Core CSS |
||||
@import "bootstrap-extended/reboot"; |
||||
@import "bootstrap-extended/helper"; |
||||
@import "bootstrap-extended/type"; |
||||
@import "bootstrap-extended/code"; |
||||
@import "bootstrap-extended/tables"; |
||||
@import "bootstrap-extended/forms"; |
||||
@import "bootstrap-extended/buttons"; |
||||
@import "bootstrap-extended/button-group"; |
||||
|
||||
// Components |
||||
@import "bootstrap-extended/dropdown"; |
||||
@import "bootstrap-extended/navbar"; |
||||
@import "bootstrap-extended/card"; |
||||
@import "bootstrap-extended/carousel"; |
||||
@import "bootstrap-extended/breadcrumb"; |
||||
@import "bootstrap-extended/badge"; |
||||
@import "bootstrap-extended/nav"; |
||||
@import "bootstrap-extended/alert"; |
||||
@import "bootstrap-extended/progress"; |
||||
@import "bootstrap-extended/list-group"; |
||||
@import "bootstrap-extended/toast"; |
||||
@import "bootstrap-extended/accordion"; |
||||
@import "bootstrap-extended/pagination"; |
||||
|
||||
// Components w/ JavaScript |
||||
@import "bootstrap-extended/modal"; |
||||
@import "bootstrap-extended/popover"; |
||||
|
||||
// Utility classes |
||||
@import "bootstrap-extended/utilities"; |
@ -1,63 +0,0 @@
|
||||
// Basic accordion |
||||
.accordion { |
||||
[data-bs-toggle='collapse'] { |
||||
font-weight: 500; |
||||
font-size: 1.1rem; |
||||
line-height: $line-height-base; |
||||
} |
||||
.accordion-item { |
||||
margin-bottom: 0; |
||||
&:last-of-type { |
||||
margin-bottom: 0; |
||||
} |
||||
&:not(:last-of-type) { |
||||
border-bottom: 1px solid $border-color; |
||||
} |
||||
} |
||||
.accordion-body { |
||||
padding-top: 0.42rem; |
||||
} |
||||
} |
||||
|
||||
// accordion without icon |
||||
.accordion { |
||||
&.accordion-without-arrow { |
||||
.accordion-button::after { |
||||
background-image: none !important; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// For Accordion with border |
||||
.accordion-border { |
||||
.accordion-item { |
||||
border: 1px solid $border-color; |
||||
border-radius: $card-border-radius; |
||||
&:not(:last-of-type) { |
||||
border-bottom: 0; |
||||
border-bottom-right-radius: 0; |
||||
border-bottom-left-radius: 0; |
||||
} |
||||
&:not(:first-of-type) { |
||||
border-top-left-radius: 0; |
||||
border-top-right-radius: 0; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// For Accordion with margin |
||||
.accordion-margin { |
||||
.accordion-item { |
||||
margin-top: 0.71rem; |
||||
margin-bottom: 0.71rem; |
||||
box-shadow: 0 2px 15px 0 rgba($black, 0.05) !important; |
||||
border-radius: $border-radius; |
||||
border-bottom: 0 solid transparent !important; |
||||
} |
||||
} |
||||
|
||||
.card.accordion-item { |
||||
.accordion-button { |
||||
border-radius: $border-radius; |
||||
} |
||||
} |
@ -1,50 +0,0 @@
|
||||
// Alerts |
||||
|
||||
.alert { |
||||
font-weight: 500; |
||||
padding: 0; |
||||
// close |
||||
&.alert-dismissible { |
||||
.btn-close { |
||||
padding: 1rem $alert-padding-x; |
||||
background-color: transparent !important; |
||||
box-shadow: none !important; |
||||
} |
||||
.alert-body { |
||||
padding: $alert-padding-y ($alert-padding-x * 2) $alert-padding-y $alert-padding-x; |
||||
} |
||||
} |
||||
.btn-close:focus { |
||||
outline: 0; |
||||
} |
||||
|
||||
.alert-link:hover { |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
// For Alert Content |
||||
p { |
||||
font-weight: 500; |
||||
padding: 2px 0; |
||||
margin-bottom: 0; |
||||
vertical-align: middle; |
||||
} |
||||
|
||||
// For alert heading |
||||
.alert-heading { |
||||
font-weight: 600; |
||||
font-size: $font-size-base; |
||||
padding: $alert-padding-y $alert-padding-x; |
||||
margin-bottom: 0; |
||||
} |
||||
.alert-body { |
||||
padding: $alert-padding-y $alert-padding-x; |
||||
} |
||||
|
||||
// For dark alert |
||||
&.alert-dark { |
||||
.alert-heading { |
||||
@include alert-heading-bs($dark); |
||||
} |
||||
} |
||||
} |
@ -1,89 +0,0 @@
|
||||
// Badge |
||||
|
||||
.badge { |
||||
&[class*='bg-'] { |
||||
[class*='icon-'] { |
||||
line-height: 1; |
||||
} |
||||
|
||||
a { |
||||
color: $white; |
||||
} |
||||
|
||||
// badge dropdown alignment |
||||
.dropdown-toggle, |
||||
&.dropdown-toggle { |
||||
span, |
||||
i, |
||||
svg { |
||||
vertical-align: text-top; |
||||
} |
||||
i, |
||||
svg { |
||||
padding-left: 0.2rem; |
||||
} |
||||
&::after { |
||||
position: relative; |
||||
top: 0; |
||||
left: 0; |
||||
font-size: 1rem; |
||||
} |
||||
} |
||||
.dropdown-menu { |
||||
a { |
||||
color: $dropdown-color; |
||||
} |
||||
} |
||||
} |
||||
|
||||
i, |
||||
svg { |
||||
height: 12px; |
||||
width: 11px; |
||||
font-size: 12px; |
||||
stroke-width: 3; |
||||
vertical-align: top; |
||||
} |
||||
|
||||
// square badge |
||||
&.badge-square { |
||||
border-radius: 0; |
||||
} |
||||
|
||||
// badge-up |
||||
// to align badge over any element |
||||
&.badge-up { |
||||
position: absolute; |
||||
top: -11px; |
||||
right: -9px; |
||||
min-width: 1.429rem; |
||||
min-height: 1.429rem; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
font-size: 0.786rem; |
||||
line-height: 0.786; |
||||
padding-left: 0.25rem; |
||||
padding-right: 0.25rem; |
||||
&.badge-sm { |
||||
top: -0.5rem; |
||||
right: -0.5rem; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// For fullscreen search |
||||
.badge-icon { |
||||
i, |
||||
svg { |
||||
font-size: 100%; |
||||
margin-right: 5px; |
||||
} |
||||
} |
||||
|
||||
// badge dropup pointer |
||||
.dropup { |
||||
.badge { |
||||
cursor: pointer; |
||||
} |
||||
} |
@ -1,80 +0,0 @@
|
||||
.breadcrumb { |
||||
&:not([class*='breadcrumb-']) { |
||||
.breadcrumb-item + .breadcrumb-item { |
||||
&:before { |
||||
content: ' '; |
||||
background-image: url(str-replace(str-replace($chevron-right, 'currentColor', $body-color), '#', '%23')); |
||||
background-repeat: no-repeat; |
||||
background-position: center; |
||||
color: $body-color; |
||||
margin-right: $breadcrumb-item-padding-x; |
||||
background-size: 14px; |
||||
} |
||||
} |
||||
} |
||||
.breadcrumb-item + .breadcrumb-item { |
||||
&:before { |
||||
height: 20px; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* Component Specific */ |
||||
.breadcrumb-slash { |
||||
&.breadcrumb { |
||||
.breadcrumb-item + .breadcrumb-item:before { |
||||
content: '/'; |
||||
} |
||||
} |
||||
} |
||||
.breadcrumb-dots { |
||||
&.breadcrumb { |
||||
.breadcrumb-item + .breadcrumb-item:before { |
||||
content: '.'; |
||||
position: relative; |
||||
top: -4px; |
||||
} |
||||
} |
||||
} |
||||
.breadcrumb-dashes { |
||||
&.breadcrumb { |
||||
.breadcrumb-item + .breadcrumb-item:before { |
||||
content: '-'; |
||||
} |
||||
} |
||||
} |
||||
.breadcrumb-pipes { |
||||
&.breadcrumb { |
||||
.breadcrumb-item + .breadcrumb-item:before { |
||||
content: '|'; |
||||
} |
||||
} |
||||
} |
||||
.breadcrumb-chevron { |
||||
&.breadcrumb { |
||||
.breadcrumb-item + .breadcrumb-item:before { |
||||
content: ' '; |
||||
background-image: url(str-replace(str-replace($chevron-right, 'currentColor', $body-color), '#', '%23')); |
||||
background-repeat: no-repeat; |
||||
background-position: center; |
||||
color: $body-color; |
||||
margin-right: $breadcrumb-item-padding-x; |
||||
background-size: 14px; |
||||
} |
||||
} |
||||
} |
||||
// padding left for header area breadcrumbs |
||||
.content-header .breadcrumb { |
||||
padding-left: 1rem; |
||||
} |
||||
|
||||
@media (max-width: 648px) { |
||||
.content-header .breadcrumb { |
||||
display: none; |
||||
} |
||||
.breadcrumbs-top { |
||||
.content-header-title { |
||||
display: contents !important; |
||||
} |
||||
} |
||||
} |
@ -1,59 +0,0 @@
|
||||
// |
||||
// Split button dropdowns |
||||
// |
||||
|
||||
.dropdown-toggle-split { |
||||
padding-right: calc($btn-padding-x / 1.9); |
||||
padding-left: calc($btn-padding-x / 1.9); |
||||
} |
||||
|
||||
.btn-lg + .dropdown-toggle-split, |
||||
.btn-group-lg > .btn + .dropdown-toggle-split { |
||||
padding-right: calc($input-btn-padding-x-lg / 1.75); |
||||
padding-left: calc($input-btn-padding-x-lg / 1.75); |
||||
} |
||||
|
||||
.btn-sm + .dropdown-toggle-split, |
||||
.btn-group-sm > .btn + .dropdown-toggle-split { |
||||
padding-right: calc($input-btn-padding-x-sm / 1.9); |
||||
padding-left: calc($input-btn-padding-x-sm / 1.9); |
||||
} |
||||
|
||||
// button group border |
||||
.btn-group { |
||||
[class*='btn-']:not([class*='btn-outline-']):not([class*='btn-flat-']):not([class*='btn-gradient-']):not([class*='btn-relief-']) { |
||||
border-left-color: rgba($black, 0.08) !important; |
||||
border-right-color: rgba($black, 0.08) !important; |
||||
} |
||||
} |
||||
|
||||
// remove first btn group border left |
||||
.btn-group |
||||
> .btn:not([class*='btn-outline-']):not([class*='btn-flat-']):not([class*='btn-gradient-']):not([class*='btn-relief-']):first-child, |
||||
.btn-group |
||||
> .btn:not([class*='btn-outline-']):not([class*='btn-flat-']):not([class*='btn-gradient-']):not([class*='btn-relief-']):first-of-type { |
||||
border-left-color: transparent !important; |
||||
} |
||||
|
||||
// remove last btn group border right |
||||
.btn-group |
||||
> .btn:not([class*='btn-outline-']):not([class*='btn-flat-']):not([class*='btn-gradient-']):not([class*='btn-relief-']):last-child, |
||||
.btn-group |
||||
> .btn:not([class*='btn-outline-']):not([class*='btn-flat-']):not([class*='btn-gradient-']):not([class*='btn-relief-']):last-of-type { |
||||
border-right-color: transparent !important; |
||||
} |
||||
|
||||
// toggle button |
||||
.btn-group-toggle { |
||||
[class*='btn-outline-'] { |
||||
&:not(:last-child) { |
||||
border-right-width: 0 !important; |
||||
} |
||||
} |
||||
:not([class*='btn-outline-']) { |
||||
&.active, |
||||
&:active { |
||||
box-shadow: inset $box-shadow; |
||||
} |
||||
} |
||||
} |
@ -1,81 +0,0 @@
|
||||
// var for box shadow of gradient buttons |
||||
// Buttons |
||||
.btn { |
||||
box-shadow: none; |
||||
font-weight: 500; |
||||
|
||||
// gradient button on hover transition |
||||
&[class*='bg-gradient-'] { |
||||
transition: all 0.2s ease; |
||||
&:hover { |
||||
transform: translateY(-2px); |
||||
} |
||||
} |
||||
|
||||
// Icon button padding |
||||
&.btn-icon { |
||||
padding: 0.715rem 0.736rem; |
||||
} |
||||
&.btn-sm { |
||||
&.btn-icon { |
||||
padding: 0.5rem; |
||||
line-height: 0.5; |
||||
} |
||||
} |
||||
&.btn-lg { |
||||
&.btn-icon { |
||||
padding: 1rem; |
||||
line-height: 0.75; |
||||
} |
||||
} |
||||
|
||||
&:focus, |
||||
&.focus, |
||||
&:active, |
||||
&.active { |
||||
outline: none; |
||||
box-shadow: none; |
||||
} |
||||
|
||||
&:not(:disabled):not(.disabled):active:focus, |
||||
&:not(:disabled):not(.disabled).active:focus { |
||||
box-shadow: none !important; |
||||
} |
||||
|
||||
// feather icons inside btn |
||||
.feather { |
||||
vertical-align: bottom; |
||||
} |
||||
} |
||||
.btn-check { |
||||
&:checked, |
||||
&:active { |
||||
+ [class*='btn-'] { |
||||
outline: none; |
||||
box-shadow: none; |
||||
} |
||||
} |
||||
} |
||||
// For Waves Input Padding |
||||
.btn.waves-input-wrapper { |
||||
padding: 0; |
||||
} |
||||
|
||||
.btn-pinned { |
||||
position: absolute; |
||||
top: 1.2rem; |
||||
right: 0.7rem; |
||||
} |
||||
|
||||
@include media-breakpoint-down(md) { |
||||
.btn-sm-block { |
||||
display: block; |
||||
width: 100%; |
||||
} |
||||
} |
||||
|
||||
// Remove cursor-pointer from button if button is disabled |
||||
// * setting it to inherit will auto adept cursor |
||||
.waves-effect { |
||||
cursor: inherit; |
||||
} |
@ -1,503 +0,0 @@
|
||||
.card { |
||||
margin-bottom: $content-padding; |
||||
box-shadow: $card-box-shadow; |
||||
transition: all 0.3s ease-in-out, background 0s, color 0s, border-color 0s; |
||||
.card { |
||||
box-shadow: none !important; |
||||
} |
||||
.card-title { |
||||
font-weight: 500; |
||||
font-size: 1.285rem; |
||||
margin-bottom: 1.53rem; // Considering sub-title minus margin |
||||
} |
||||
.card-bordered { |
||||
border: $card-border-width solid $card-border-color; |
||||
} |
||||
.card-img { |
||||
object-fit: cover; |
||||
} |
||||
.card-img-overlay { |
||||
border-radius: $card-border-radius; |
||||
} |
||||
|
||||
//fullscreen card |
||||
&.card-fullscreen { |
||||
display: block; |
||||
z-index: 9999; |
||||
position: fixed; |
||||
width: 100% !important; |
||||
height: 100% !important; |
||||
top: 0; |
||||
right: 0; |
||||
left: 0; |
||||
bottom: 0; |
||||
overflow: auto; |
||||
} |
||||
.card-body[class*='border-bottom-'] { |
||||
border-bottom-width: 2px !important; |
||||
} |
||||
.card-img-overlay { |
||||
&.bg-overlay { |
||||
background: rgba($black, 0.45); |
||||
} |
||||
.text-muted { |
||||
color: $gray-800 !important; |
||||
} |
||||
} |
||||
&.card-minimal { |
||||
border: none; |
||||
box-shadow: none; |
||||
} |
||||
|
||||
.card-header { |
||||
position: relative; |
||||
display: flex; |
||||
align-items: center; |
||||
flex-wrap: wrap; |
||||
justify-content: space-between; |
||||
.card-title { |
||||
margin-bottom: 0; |
||||
} |
||||
|
||||
.heading-elements { |
||||
position: relative; |
||||
top: -1px; |
||||
|
||||
li:not(:first-child) a { |
||||
margin-left: 0.75rem; |
||||
} |
||||
|
||||
a { |
||||
&.btn { |
||||
padding-top: 6px; |
||||
padding-bottom: 6px; |
||||
} |
||||
i, |
||||
svg { |
||||
height: 1rem; |
||||
width: 1rem; |
||||
font-size: 1rem; |
||||
} |
||||
&[data-action='collapse'] { |
||||
i, |
||||
svg { |
||||
transition: all 0.25s ease-out; |
||||
display: inline-block; |
||||
} |
||||
&.rotate { |
||||
i, |
||||
svg { |
||||
transform: rotate(-180deg); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
& + .card-content > .card-body:first-of-type, |
||||
& + .card-body { |
||||
padding-top: 0px; |
||||
} |
||||
} |
||||
.card-footer { |
||||
border-top: 1px solid $gray-300; |
||||
background-color: transparent; |
||||
} |
||||
} |
||||
|
||||
.card-group { |
||||
margin-bottom: 0.75rem; |
||||
} |
||||
|
||||
.card-head-inverse { |
||||
.heading-elements { |
||||
i, |
||||
svg { |
||||
color: $white; |
||||
} |
||||
} |
||||
color: $white; |
||||
} |
||||
.card-transparent { |
||||
background-color: transparent; |
||||
} |
||||
|
||||
.text-white { |
||||
.card-img-overlay { |
||||
.text-muted { |
||||
color: $white !important; |
||||
} |
||||
} |
||||
code { |
||||
background-color: rgba($white, 1); |
||||
} |
||||
.heading-elements { |
||||
i, |
||||
svg { |
||||
color: $white; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// overlay-img-card |
||||
.overlay-img-card { |
||||
.card-img-overlay, |
||||
img { |
||||
max-height: 34.64rem; |
||||
} |
||||
} |
||||
|
||||
// IE Specific CSS |
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { |
||||
// img-fluid class |
||||
.card-body, |
||||
.card-content { |
||||
min-height: 1px; |
||||
} |
||||
} |
||||
|
||||
//--------------- Advance Cards --------------- |
||||
//--------------------------------------------- |
||||
|
||||
// Congratulations Card |
||||
.card-congratulations { |
||||
background: linear-gradient(118deg, rgba($primary, 1), rgba($primary, 0.7)); |
||||
color: $white; |
||||
|
||||
// image on left |
||||
.congratulations-img-left { |
||||
width: 200px; |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
|
||||
@include media-breakpoint-down(sm) { |
||||
width: 140px; |
||||
} |
||||
} |
||||
// image on right |
||||
.congratulations-img-right { |
||||
width: 175px; |
||||
position: absolute; |
||||
top: 0; |
||||
right: 0; |
||||
|
||||
@include media-breakpoint-down(sm) { |
||||
width: 140px; |
||||
} |
||||
} |
||||
|
||||
.avatar { |
||||
margin-bottom: 2rem; |
||||
} |
||||
} |
||||
// congratulation medal card |
||||
.congratulation-medal { |
||||
position: absolute; |
||||
top: 0; |
||||
right: 37px; |
||||
} |
||||
|
||||
// Deposits Card |
||||
.card-deposits { |
||||
.deposits-divider { |
||||
margin-top: 1.8rem; |
||||
margin-bottom: 1.4rem; |
||||
} |
||||
} |
||||
|
||||
// Employee Task Card |
||||
.card-employee-task { |
||||
.employee-task { |
||||
&:not(:last-child) { |
||||
margin-bottom: 1.5rem; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Developer Meetup Card |
||||
.card-developer-meetup { |
||||
.meetup-img-wrapper { |
||||
background-color: rgba($primary, 0.1); |
||||
} |
||||
.meetup-header { |
||||
margin-bottom: 2rem; |
||||
|
||||
.meetup-day { |
||||
text-align: center; |
||||
border-right: 1px solid $input-border-color; |
||||
padding-right: 1.3rem; |
||||
margin-right: 1.3rem; |
||||
} |
||||
} |
||||
.meetings { |
||||
.avatar .avatar-content { |
||||
width: 34px; |
||||
height: 34px; |
||||
} |
||||
& + .meetings { |
||||
margin-top: 1.2rem; |
||||
} |
||||
} |
||||
.avatar-group { |
||||
margin-top: 2rem; |
||||
} |
||||
} |
||||
|
||||
// Profile Card |
||||
.card-profile { |
||||
text-align: center; |
||||
.card-body { |
||||
position: relative; |
||||
padding: 5rem 2.3rem $card-spacer-y 2.3rem; |
||||
|
||||
.profile-image-wrapper { |
||||
display: flex; |
||||
justify-content: center; |
||||
|
||||
.profile-image { |
||||
position: absolute; |
||||
top: -4rem; |
||||
padding: 0.5rem; |
||||
border-radius: 50%; |
||||
background-color: $white; |
||||
box-shadow: 0 0 8px 0 rgba($black, 0.14); |
||||
margin-bottom: 1.15rem; |
||||
|
||||
img { |
||||
width: 100px; |
||||
height: 100px; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.profile-badge { |
||||
margin-top: 0.8rem; |
||||
margin-bottom: 0.8rem; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Apply Job Card |
||||
.card-apply-job { |
||||
.apply-job-package { |
||||
padding: 1.2rem; |
||||
margin-bottom: 1.15rem; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
sup { |
||||
top: -0.8rem; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Transaction Card |
||||
.card-transaction { |
||||
.transaction-item { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
&:not(:last-child) { |
||||
margin-bottom: 1.2rem; |
||||
} |
||||
|
||||
.avatar { |
||||
margin-right: 1.2rem; |
||||
.avatar-content { |
||||
width: 42px; |
||||
height: 42px; |
||||
} |
||||
} |
||||
|
||||
.transaction-title { |
||||
margin-bottom: 0.2rem; |
||||
margin-top: 0.2rem; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// User Timeline Card |
||||
.card-user-timeline { |
||||
.user-timeline-title-icon { |
||||
width: 1.714rem; |
||||
height: 1.714rem; |
||||
margin-right: 1.3rem; |
||||
} |
||||
.timeline { |
||||
.timeline-item { |
||||
&:last-child { |
||||
.timeline-event { |
||||
min-height: auto; |
||||
} |
||||
} |
||||
&:not(:last-child) { |
||||
padding-bottom: 2.3rem; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Business Card |
||||
.business-card { |
||||
.business-items { |
||||
&:not(:last-child) { |
||||
margin-bottom: 1.3rem; |
||||
} |
||||
|
||||
.business-item { |
||||
border: 1px solid $border-color; |
||||
border-radius: $border-radius; |
||||
padding: 1rem 1rem 1rem 1.3rem; |
||||
&:not(:last-child) { |
||||
margin-bottom: 0.85rem; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// States Card |
||||
.card-browser-states { |
||||
.browser-states { |
||||
margin-top: 2.14rem; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
} |
||||
} |
||||
|
||||
// App Design Card |
||||
.card-app-design { |
||||
.design-group { |
||||
margin-bottom: 2rem; |
||||
|
||||
.avatar:not(:last-child) { |
||||
margin-right: 0.6rem; |
||||
} |
||||
} |
||||
|
||||
.design-planning-wrapper { |
||||
display: flex; |
||||
align-items: center; |
||||
flex-wrap: wrap; |
||||
&:not(:last-child) { |
||||
margin-bottom: 1.3rem; |
||||
} |
||||
|
||||
.design-planning { |
||||
padding: 0.5rem; |
||||
margin-bottom: 0.7rem; |
||||
text-align: center; |
||||
background-color: $body-bg; |
||||
border-radius: $border-radius; |
||||
min-width: 6.4rem; |
||||
&:not(:last-child) { |
||||
margin-right: 0.7rem; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
//--------------- Statistics Card --------------- |
||||
//------------------------------------------------ |
||||
|
||||
.card-statistics { |
||||
.card-header { |
||||
padding-left: 2.4rem; |
||||
} |
||||
.statistics-body { |
||||
padding: 2rem 2.4rem 2.8rem !important; |
||||
|
||||
.avatar .avatar-content { |
||||
width: 48px; |
||||
height: 48px; |
||||
|
||||
.avatar-icon { |
||||
width: 24px; |
||||
height: 24px; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
//--------------- Analytics Card --------------- |
||||
//---------------------------------------------- |
||||
|
||||
// Chart-dropdown Button |
||||
.chart-dropdown { |
||||
.btn { |
||||
font-size: 1rem; |
||||
font-weight: $font-weight-normal; |
||||
&:after { |
||||
display: none; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Revenue Report & Budget Card |
||||
.card-revenue-budget { |
||||
.revenue-report-wrapper { |
||||
padding: 1.286rem 1.5rem; |
||||
|
||||
@include media-breakpoint-up(md) { |
||||
border-right: 1px solid $border-color; |
||||
} |
||||
|
||||
#revenue-report-chart { |
||||
.apexcharts-series { |
||||
&[seriesName='Earning'] { |
||||
transform: scaleY(0.965); |
||||
} |
||||
&[seriesName='Expense'] { |
||||
transform: scaleY(1.035); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.budget-wrapper { |
||||
padding: 2rem 3rem; |
||||
text-align: center; |
||||
|
||||
@include media-breakpoint-down(md) { |
||||
padding-top: 0; |
||||
} |
||||
|
||||
.budget-dropdown { |
||||
margin-bottom: 2rem; |
||||
} |
||||
|
||||
#budget-chart { |
||||
margin-top: 2rem; |
||||
margin-bottom: 2rem; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Earnings Card |
||||
.earnings-card { |
||||
.apexcharts-canvas .apexcharts-pie { |
||||
.apexcharts-datalabel-label { |
||||
font-size: 0.8rem; |
||||
fill: $body-color !important; |
||||
} |
||||
.apexcharts-datalabel-value { |
||||
fill: $headings-color; |
||||
font-size: 1.286rem; |
||||
font-weight: 500; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// IE Specific CSS |
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { |
||||
// make icon center in avatar-content |
||||
#dashboard-analytics, |
||||
#statistics-card { |
||||
.avatar { |
||||
.avatar-content { |
||||
padding: 0 !important; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,5 +0,0 @@
|
||||
// .carousel-dark .carousel-caption{ |
||||
// h1, h2, h3, h4, h5, h6{ |
||||
// color: $carousel-dark-caption-color; |
||||
// } |
||||
// } |
@ -1,14 +0,0 @@
|
||||
// Inline code |
||||
code { |
||||
padding: 0.1rem 0.4rem; |
||||
font-size: 90%; |
||||
color: $code-color; |
||||
background-color: $kbd-bg; |
||||
@include border-radius(calc($border-radius/2)); |
||||
} |
||||
pre { |
||||
background-color: #f7f7f9; |
||||
code { |
||||
background-color: transparent !important; |
||||
} |
||||
} |
@ -1,255 +0,0 @@
|
||||
// The dropdown menu |
||||
.dropdown { |
||||
[class*='btn-outline-'].dropdown-toggle.dropdown-toggle-split { |
||||
border-left: 0 !important; |
||||
} |
||||
|
||||
// If don't won't dropdown/up arrow |
||||
&.no-arrow { |
||||
.dropdown-toggle { |
||||
&:after { |
||||
display: none; |
||||
} |
||||
i, |
||||
svg { |
||||
margin-right: 0; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// dropdown menu |
||||
.dropdown-menu { |
||||
transform: scale(1, 0); |
||||
box-shadow: $dropdown-box-shadow; // this according to vue version |
||||
|
||||
.dropdown-item { |
||||
width: auto; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
// Dropdown Header |
||||
.dropdown-header { |
||||
font-weight: 500; |
||||
line-height: 1; |
||||
} |
||||
} |
||||
|
||||
.show { |
||||
> .dropdown-menu { |
||||
transform: scale(1, 1); |
||||
opacity: 1; |
||||
display: block; |
||||
} |
||||
.dropdown-toggle { |
||||
&:focus { |
||||
box-shadow: none; |
||||
} |
||||
} |
||||
|
||||
// For DD box shadow on show |
||||
.btn { |
||||
&.dropdown-toggle { |
||||
&:focus { |
||||
box-shadow: none; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.dropdown-toggle { |
||||
// changed icon caret |
||||
|
||||
&::after { |
||||
border: none !important; |
||||
content: ' '; |
||||
background-image: url(str-replace(str-replace($chevron-down, 'currentColor', $white), '#', '%23')); |
||||
background-repeat: no-repeat; |
||||
background-position: center; |
||||
background-size: 16px; |
||||
color: $body-color; |
||||
width: 14px; |
||||
height: 11px; |
||||
position: relative; |
||||
top: 1px; |
||||
right: 0px; |
||||
left: 0.714rem; |
||||
padding: 0; |
||||
margin: 0; |
||||
vertical-align: 0; |
||||
} |
||||
// arrow size according to toggle sizes |
||||
&.btn-lg { |
||||
&::after { |
||||
background-size: 18px; |
||||
} |
||||
} |
||||
|
||||
&.btn-sm { |
||||
&::after { |
||||
background-size: 14px; |
||||
} |
||||
} |
||||
|
||||
&.dropdown-toggle-split { |
||||
&:after { |
||||
left: 0; |
||||
} |
||||
} |
||||
|
||||
// hide default arrow to show custom icon DD |
||||
&.nav-hide-arrow { |
||||
&::after { |
||||
display: none; |
||||
} |
||||
} |
||||
|
||||
// Prevent the focus on the dropdown toggle when closing dropdowns |
||||
&:focus { |
||||
outline: 0; |
||||
} |
||||
} |
||||
|
||||
// DropUp |
||||
.dropup { |
||||
position: relative; |
||||
.dropdown-toggle { |
||||
// changed icon dropup caret |
||||
&::after { |
||||
background-image: url(str-replace(str-replace($chevron-up, 'currentColor', $white), '#', '%23')); |
||||
background-repeat: no-repeat; |
||||
background-position: center; |
||||
background-size: 16px; |
||||
width: 14px; |
||||
height: 11px; |
||||
content: ''; |
||||
vertical-align: 0.05rem; |
||||
} |
||||
} |
||||
.dropdown-menu { |
||||
min-width: 8rem; |
||||
} |
||||
} |
||||
|
||||
// DropStart |
||||
.dropstart { |
||||
.dropdown-toggle { |
||||
// changed icon dropup caret |
||||
&::before { |
||||
border: none !important; |
||||
background-image: url(str-replace(str-replace($chevron-left, 'currentColor', $white), '#', '%23')); |
||||
background-repeat: no-repeat; |
||||
background-position: center; |
||||
background-size: 16px; |
||||
width: 14px; |
||||
height: 11px; |
||||
content: ''; |
||||
position: relative; |
||||
left: 0; |
||||
} |
||||
} |
||||
.dropdown-menu { |
||||
min-width: 8rem; |
||||
} |
||||
} |
||||
|
||||
// DropEnd |
||||
.dropend { |
||||
.dropdown-toggle { |
||||
// changed icon dropup caret |
||||
&::after { |
||||
border: none !important; |
||||
background-image: url(str-replace(str-replace($chevron-right, 'currentColor', $white), '#', '%23')); |
||||
background-repeat: no-repeat; |
||||
background-position: center; |
||||
background-size: 16px; |
||||
width: 14px; |
||||
height: 11px; |
||||
content: ''; |
||||
} |
||||
} |
||||
.dropdown-menu { |
||||
min-width: 8rem; |
||||
} |
||||
} |
||||
|
||||
// Dropdown ::before position |
||||
.dropdown-menu { |
||||
// Dropdown margin according to dropdown position |
||||
|
||||
&[data-popper-placement='bottom-start'], |
||||
&[data-popper-placement='bottom-end'] { |
||||
margin-top: $dropdown_spacing !important; |
||||
} |
||||
|
||||
&[data-popper-placement='top-start'], |
||||
&[data-popper-placement='top-end'] { |
||||
margin-bottom: $dropdown_spacing !important; |
||||
} |
||||
|
||||
&[data-popper-placement='right-start'], |
||||
&[data-popper-placement='right-end'] { |
||||
margin-left: $dropdown_spacing !important; |
||||
} |
||||
&[data-popper-placement='left-start'], |
||||
&[data-popper-placement='left-end'] { |
||||
margin-right: $dropdown_spacing !important; |
||||
} |
||||
} |
||||
|
||||
// Dropdown icon |
||||
.dropdown, |
||||
.dropup { |
||||
&.dropdown-icon-wrapper { |
||||
.dropdown-toggle { |
||||
&:after { |
||||
display: none; |
||||
} |
||||
} |
||||
.dropdown-menu { |
||||
min-width: auto; |
||||
.dropdown-item { |
||||
padding: 0.5rem 1.1rem; |
||||
cursor: pointer; |
||||
i, |
||||
svg { |
||||
height: 1.3rem; |
||||
width: 1.3rem; |
||||
font-size: 1.3rem; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Dropdown menu animation for Horizontal menu |
||||
.horizontal-menu-wrapper .dropdown-menu, |
||||
.header-navbar .dropdown-menu { |
||||
animation-duration: 0.3s; |
||||
animation-fill-mode: both; |
||||
animation-name: slideIn; |
||||
} |
||||
|
||||
// Hidden dropdown toggle arrow |
||||
.dropdown-toggle.hide-arrow, |
||||
.dropdown-toggle-hide-arrow > .dropdown-toggle { |
||||
&::before, |
||||
&::after { |
||||
display: none; |
||||
} |
||||
} |
||||
|
||||
@keyframes slideIn { |
||||
0% { |
||||
transform: translateY(1rem); |
||||
opacity: 0; |
||||
} |
||||
100% { |
||||
transform: translateY(0rem); |
||||
opacity: 1; |
||||
} |
||||
0% { |
||||
transform: translateY(1rem); |
||||
opacity: 0; |
||||
} |
||||
} |
@ -1,58 +0,0 @@
|
||||
// placeholder specific scss |
||||
@import 'forms/labels'; |
||||
@import 'forms/form-control'; |
||||
@import 'forms/input-group'; |
||||
@import 'forms/form-check'; |
||||
@import 'forms/floating-labels'; |
||||
|
||||
// Custom third party form plugin scss |
||||
|
||||
/* Textarea with Counter */ |
||||
.textarea-counter-value { |
||||
background-color: $primary; |
||||
color: $white; |
||||
padding: 1px 6px; |
||||
font-size: 0.6rem; |
||||
border-radius: 0 0 5px 5px; |
||||
margin-right: 1rem; |
||||
} |
||||
|
||||
// Number Input style |
||||
.btn.disabled-max-min, |
||||
.btn.disabled-max-min:focus, |
||||
.btn.disabled-max-min:active { |
||||
background-color: rgba($black, 0.5) !important; |
||||
cursor: default; |
||||
} |
||||
|
||||
// disabled number input |
||||
.bootstrap-touchspin, |
||||
.bootstrap-touchspin { |
||||
&.disabled-touchspin { |
||||
.bootstrap-touchspin-down, |
||||
.bootstrap-touchspin-up { |
||||
border-color: transparent !important; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* Number Type Input Box Scss for - Remove arrow on hover */ |
||||
input[type='number']::-webkit-inner-spin-button, |
||||
input[type='number']::-webkit-outer-spin-button { |
||||
-webkit-appearance: none; |
||||
} |
||||
|
||||
// Date & Time Picker - Form Control Bg color |
||||
.picker__input { |
||||
&.form-control { |
||||
background-color: $white; |
||||
} |
||||
} |
||||
|
||||
// Autofill style |
||||
input:-webkit-autofill, |
||||
textarea:-webkit-autofill, |
||||
select:-webkit-autofill { |
||||
-webkit-box-shadow: 0 0 0 1000px $white inset !important; |
||||
-webkit-text-fill-color: $body-color !important; |
||||
} |
@ -1,10 +0,0 @@
|
||||
@function str-replace($string, $search, $replace: '') { |
||||
$index: str-index($string, $search); |
||||
|
||||
@if $index { |
||||
@return str-slice($string, 1, $index - 1) + $replace + |
||||
str-replace(str-slice($string, $index + str-length($search)), $search, $replace); |
||||
} |
||||
|
||||
@return $string; |
||||
} |
@ -1,106 +0,0 @@
|
||||
// ================================================================================================ |
||||
// File Name: helper.scss |
||||
// Description: Helper classes provides template related customization. |
||||
// ---------------------------------------------------------------------------------------------- |
||||
// Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template |
||||
// Author: PIXINVENT |
||||
// Author URL: http://www.themeforest.net/user/pixinvent |
||||
// ================================================================================================ |
||||
|
||||
// Content helpers |
||||
// ------------------------- |
||||
|
||||
// typography page icon with list |
||||
.list-style-icons { |
||||
padding-left: 10px; |
||||
margin-left: 0; |
||||
list-style: none; |
||||
> li svg, |
||||
> li i { |
||||
margin-right: 6px; |
||||
} |
||||
} |
||||
|
||||
//Pull the element |
||||
.pull-up { |
||||
transition: all 0.25s ease; |
||||
|
||||
&:hover { |
||||
transform: translateY(-4px) scale(1.02); |
||||
box-shadow: 0px 14px 24px rgba(62, 57, 107, 0.2); |
||||
z-index: 30; |
||||
} |
||||
} |
||||
|
||||
// Spinner classes |
||||
.spinner { |
||||
display: inline-block; |
||||
animation: spin 1s linear infinite; |
||||
} |
||||
@keyframes spin { |
||||
0% { |
||||
transform: rotate(0deg); |
||||
} |
||||
100% { |
||||
transform: rotate(360deg); |
||||
} |
||||
} |
||||
|
||||
.spinner-reverse { |
||||
display: inline-block; |
||||
animation: spin-reverse 1s linear infinite; |
||||
} |
||||
@keyframes spin-reverse { |
||||
0% { |
||||
transform: rotate(0deg); |
||||
} |
||||
100% { |
||||
transform: rotate(-360deg); |
||||
} |
||||
} |
||||
|
||||
// Bullets used in application pages |
||||
.bullet { |
||||
width: 1rem; |
||||
height: 1rem; |
||||
border-radius: 50%; |
||||
display: inline-block; |
||||
&.bullet-xs { |
||||
width: 0.5rem; |
||||
height: 0.5rem; |
||||
} |
||||
&.bullet-sm { |
||||
width: 0.714rem; |
||||
height: 0.714rem; |
||||
} |
||||
&.bullet-lg { |
||||
width: 1.25rem; |
||||
height: 1.25rem; |
||||
} |
||||
} |
||||
|
||||
// Section Label - used in pages and apps |
||||
.section-label { |
||||
font-size: 0.85rem; |
||||
color: $text-muted; |
||||
text-transform: uppercase; |
||||
letter-spacing: 0.6px; |
||||
} |
||||
|
||||
// Used for table cell fit |
||||
.cell-fit { |
||||
width: 0.1%; |
||||
white-space: nowrap; |
||||
} |
||||
|
||||
// Card match height |
||||
.match-height { |
||||
> [class*='col'] { |
||||
display: flex; |
||||
flex-flow: column; |
||||
|
||||
> .card { |
||||
flex: 1 1 auto; |
||||
} |
||||
} |
||||
} |
@ -1,24 +0,0 @@
|
||||
// ================================================================================================ |
||||
// File Name: include.scss |
||||
// Description: Common components file to include all theme specific custom components. |
||||
// ---------------------------------------------------------------------------------------------- |
||||
// Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template |
||||
// Author: PIXINVENT |
||||
// Author URL: http://www.themeforest.net/user/pixinvent |
||||
// ================================================================================================ |
||||
|
||||
// Variables |
||||
// ------------------------------ |
||||
|
||||
// Functions |
||||
@import 'bootstrap/scss/functions'; // Bootstrap core function |
||||
@import 'functions'; // Bootstrap extended function |
||||
|
||||
// Variables |
||||
@import '../../../scss/variables/variables'; // Bootstrap custom variable override (for user purpose) |
||||
@import 'variables'; // Bootstrap extended variable override |
||||
@import 'bootstrap/scss/variables'; // Bootstrap core variable |
||||
|
||||
// Mixins |
||||
@import 'bootstrap/scss/mixins'; // Bootstrap core mixins |
||||
@import 'mixins'; // Bootstrap extended mixins |
@ -1,79 +0,0 @@
|
||||
/* =============================================================================================== |
||||
File Name: list-group.scss |
||||
Description: Contain list item, list group related extended SCSS. |
||||
---------------------------------------------------------------------------------------------- |
||||
Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template |
||||
Author: PIXINVENT |
||||
Author URL: http://www.themeforest.net/user/pixinvent |
||||
================================================================================================*/ |
||||
|
||||
// Inline list style with pipeline separator |
||||
|
||||
ul.list-inline { |
||||
li { |
||||
display: inline-block; |
||||
} |
||||
// used in search page |
||||
&.list-inline-pipe { |
||||
> li + li:before { |
||||
content: ' | '; |
||||
padding-right: 2px; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// bootstrap list group |
||||
.list-group { |
||||
.list-group-item { |
||||
line-height: 1.5; |
||||
i, |
||||
svg { |
||||
position: relative; |
||||
} |
||||
} |
||||
.list-group-item-action { |
||||
&:focus { |
||||
outline: 0; |
||||
} |
||||
&.active, |
||||
&:active{ |
||||
h1,h2,h3,h4,h5,h6{ |
||||
color: $white; |
||||
} |
||||
} |
||||
small { |
||||
color: $text-muted !important; |
||||
} |
||||
} |
||||
|
||||
// List group with circle for pages like knowledge base |
||||
&.list-group-circle { |
||||
border: none; |
||||
.list-group-item { |
||||
border: none; |
||||
position: relative; |
||||
padding-left: 1.5rem; |
||||
&:after { |
||||
content: ' '; |
||||
background-image: url(str-replace(str-replace($circle, 'currentColor', $body-color), '#', '%23')); |
||||
background-repeat: no-repeat; |
||||
background-position: center; |
||||
color: $body-color; |
||||
background-size: 10px; |
||||
position: absolute; |
||||
height: 10px; |
||||
width: 10px; |
||||
top: 1.15rem; |
||||
left: 0; |
||||
} |
||||
&:hover { |
||||
background-color: transparent; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// for drag and drop border radius on selected |
||||
.list-group-item.gu-mirror { |
||||
border-radius: 0; |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue