progres sampai penjadwalan karyawan

This commit is contained in:
Zamzam Nurzaman 2024-08-29 17:07:55 +07:00
parent 66e3c51bdc
commit 5a24d308ff
19 changed files with 964 additions and 156 deletions

View File

@ -10,7 +10,7 @@ const nextConfig = {
},
transpilePackages: ["next-image-export-optimizer"],
env: {
nextImageExportOptimizer_imageFolderPath: "public/images",
nextImageExportOptimizer_imageFolderPath: "public",
nextImageExportOptimizer_exportFolderPath: "out",
nextImageExportOptimizer_quality: "75",
nextImageExportOptimizer_storePicturesInWEBP: "true",
@ -45,6 +45,7 @@ const { withSentryConfig } = require("@sentry/nextjs");
module.exports = withSentryConfig(
module.exports,
{
enabled: process.env.NODE_ENV === 'production',
// For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options

15
package-lock.json generated
View File

@ -11,6 +11,7 @@
"@ant-design/icons": "^5.3.0",
"@sentry/nextjs": "^8.26.0",
"antd": "^5.12.5",
"apexcharts": "^3.49.1",
"cookies-next": "^4.1.1",
"dayjs": "^1.11.10",
"docxtemplater": "^3.40.0",
@ -4072,8 +4073,7 @@
"node_modules/@yr/monotone-cubic-spline": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz",
"integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==",
"peer": true
"integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA=="
},
"node_modules/acorn": {
"version": "8.12.1",
@ -4236,7 +4236,6 @@
"version": "3.52.0",
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.52.0.tgz",
"integrity": "sha512-7dg0ADKs8AA89iYMZMe2sFDG0XK5PfqllKV9N+i3hKHm3vEtdhwz8AlXGm+/b0nJ6jKiaXsqci5LfVxNhtB+dA==",
"peer": true,
"dependencies": {
"@yr/monotone-cubic-spline": "^1.0.3",
"svg.draggable.js": "^2.2.2",
@ -9429,7 +9428,6 @@
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
"integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==",
"peer": true,
"dependencies": {
"svg.js": "^2.0.1"
},
@ -9441,7 +9439,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz",
"integrity": "sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==",
"peer": true,
"dependencies": {
"svg.js": ">=2.3.x"
},
@ -9453,7 +9450,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz",
"integrity": "sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==",
"peer": true,
"dependencies": {
"svg.js": "^2.2.5"
},
@ -9464,14 +9460,12 @@
"node_modules/svg.js": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz",
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==",
"peer": true
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA=="
},
"node_modules/svg.pathmorphing.js": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz",
"integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==",
"peer": true,
"dependencies": {
"svg.js": "^2.4.0"
},
@ -9483,7 +9477,6 @@
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz",
"integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==",
"peer": true,
"dependencies": {
"svg.js": "^2.6.5",
"svg.select.js": "^2.1.2"
@ -9496,7 +9489,6 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz",
"integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==",
"peer": true,
"dependencies": {
"svg.js": "^2.2.5"
},
@ -9508,7 +9500,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz",
"integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==",
"peer": true,
"dependencies": {
"svg.js": "^2.6.5"
},

View File

@ -250,7 +250,7 @@ section {
.ant-upload-select {
background-color: #ffffff !important;
border: 1px solid #e1e3ea !important;
//border: 1px solid #e1e3ea !important;
overflow: hidden;
}
@ -1817,3 +1817,7 @@ section {
.ant-spin .ant-spin-dot-holder {
color: var(--primary);
}
hr.border{
border: 1px dashed #e9e9e9;
}

View File

@ -1 +1 @@
{"version":3,"file":"sw.js","sources":["../../../Users/modern/AppData/Local/Temp/d3da5137cc0f02db0dee33dd804e57ce/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from 'C:/laragon/www/das/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from 'C:/laragon/www/das/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from 'C:/laragon/www/das/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from 'C:/laragon/www/das/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"}
{"version":3,"file":"sw.js","sources":["C:/Users/Zame/AppData/Local/Temp/54f006ce701c372e5d85677bc3eb65a7/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from 'E:/JS PROJECT/das/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from 'E:/JS PROJECT/das/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from 'E:/JS PROJECT/das/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from 'E:/JS PROJECT/das/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"}

View File

@ -1,9 +0,0 @@
import { NextResponse } from "next/server";
export const dynamic = "force-dynamic";
// A faulty API route to test Sentry's error monitoring
export function GET() {
throw new Error("Sentry Example API Route Error");
return NextResponse.json({ data: "Testing Sentry Error..." });
}

View File

@ -0,0 +1,142 @@
import {useForm} from "react-hook-form";
import {useEffect, useState} from "react";
import {Button, Col, Modal, Row, Spin, TimePicker, Upload} from "antd";
import {CloseOutlined, UploadOutlined} from "@ant-design/icons";
import Input from "@/components/util/Input";
import "./style.scss";
import {DropdownAPI} from "@/lib/DropdownAPI";
const {RangePicker} = TimePicker;
export default function FormModal({modalStatus, actClose, data, loadingModal, jenis}) {
const [viewReadonly, setViewReadonly] = useState(false)
const [dropdownLoading, setDropdownLoading] = useState(false)
const [dropdown, setDropdown] = useState({
jabatanId: [], karyawanId: [], jenisId: []
})
const [fileList, setFileList] = useState(null);
const props = {
onRemove: (file) => {
const index = fileList.indexOf(file);
const newFileList = fileList.slice();
newFileList.splice(index, 1);
setFileList(newFileList);
},
beforeUpload: (file) => {
console.log(file)
setFileList([file]);
return false;
},
fileList,
};
const {
register, setValue, watch, getValues, formState: {errors},
} = useForm();
const dropdownInit = async () => {
setDropdownLoading(true)
let listJabatan = await DropdownAPI.jabatan();
let listKaryawan = await DropdownAPI.karyawan();
let listJenis = await DropdownAPI.jenisPenjadwalan();
setDropdown({
jabatanId: listJabatan, karyawanId: listKaryawan, jenisId: listJenis,
})
setDropdownLoading(false)
}
const TypeAction = () => {
if (jenis === 'detail') {
return (<></>)
} else {
return (<button className="btn btn-primary btn-sm">Simpan</button>)
}
}
useEffect(() => {
if (jenis === 'detail') {
setViewReadonly(true);
} else {
setViewReadonly(false);
}
}, [jenis]);
useEffect(() => {
dropdownInit()
}, []);
return (<Modal centered closeIcon={false} open={modalStatus} width={"500px"} footer={null}>
<Spin spinning={loadingModal}>
<div className="btn btn-circle btn-light-primary zn-close" onClick={actClose}>
<CloseOutlined/>
</div>
<div className="px-6 py-4 cardDark">
<div className="fs-6 fw-bolder text-uppercase text-primary">Data Penjadwalan</div>
<div className="fs-7 fw-ligth text-muted">Data Penjadwalan</div>
<div className="separator my-3"/>
<div style={{overflowY: 'auto', overflowX: 'hidden', height: '600px'}} className="my-4 p-2">
<Row gutter={15}>
<Col span={24}>
<Input.Select title={"Jenis"}
name={"jenisId"}
val={watch("jenisId")}
loading={dropdownLoading}
options={dropdown?.jenisId}
required setValue={setValue}
register={register}
error={errors}/>
</Col>
<Col span={24}>
<Input.DateRange title={"Mulai - Selesai"} name={"date"} setValue={setValue} required register={register} error={errors}/>
</Col>
<Col span={24}>
<Input.Textarea title={"Keterangan"} name={"keterangan"} required register={register} error={errors}/>
</Col>
<Col span={24}>
<Input.Select title={"Jabatan"}
name={"jabatanId"}
val={watch("jabatanId")}
loading={dropdownLoading}
options={dropdown?.jabatanId}
required setValue={setValue}
register={register}
error={errors}/>
</Col>
<Col span={24}>
<Input.Select setMultiple
title={"Pilih Karyawan"}
name={"karyawanId"}
val={watch("karyawanId")}
loading={dropdownLoading}
options={dropdown?.karyawanId}
required setValue={setValue}
register={register}
error={errors}/>
</Col>
<Col span={24}>
<hr className={"border mt-3 mb-4"}/>
<Upload {...props} listType={"picture"} multiple={false} >
<button type={"button"} className={"btn btn-light-primary btn-sm"}>Pilih Dokumen / File Pendukung</button>
{/*<Button style={{width:'100%',borderRadius:'20px'}} icon={<UploadOutlined />}>Pilih Dokumen / File</Button>*/}
</Upload>
</Col>
</Row>
</div>
</div>
<div className="card-footer text-right py-3 px-5 zn-bg-modal">
<TypeAction/>
</div>
</Spin>
</Modal>
)
}

View File

@ -0,0 +1,182 @@
"use client"
import {useEffect, useState} from "react";
import {Helper} from "@/lib/Helper";
import WrapperContent from "@/components/util/WrapperContent";
import SearchInput from "@/components/util/SearchInput";
import {API} from "@/lib/API";
import notifStore from "@/store/notifStore";
import {EditOutlined, PlusCircleOutlined, ReloadOutlined, SettingOutlined} from "@ant-design/icons";
import {Col, Dropdown} from "antd";
import FormModal from "./FormModal";
import DTAntServerSide from "@/components/util/DTAntServerSide";
import Input from "@/components/util/Input";
import {DropdownAPI} from "@/lib/DropdownAPI";
import {useForm} from "react-hook-form";
export default function Page() {
const {notifOpen} = notifStore()
const [searchText, setSearchText] = useState(null);
const [trigerGetData, setTrigerGetData] = useState(0)
const [loadingTable, setLoadingTable] = useState(true)
const [dropdownLoading, setDropdownLoading] = useState(false)
const [dropdown, setDropdown] = useState({
jabatanId: [], karyawanId: [], jenisId: []
})
const {
register, setValue, watch, getValues, formState: {errors},
} = useForm();
const [modal, setModal] = useState({
loadingModal:false,
modalStatus:false,
jenis:null,
data:[]
})
const [tableColumn, setTableColumn] = useState([
{
title: "Tanggal Dibuat", render: (_, row) => (Helper.formatDate(row.crtdt, 'd-M-Y H:i:s'))
}, {
title: "Nama Karyawan", render: (_, row) => ("Zamzam")
}, {
title: "Jabatan", render: (_, row) => ("Staf")
}, {
title: "Jenis", render: (_, row) => ("Dinas")
}, {
title: "Lama", render: (_, row) => ("5 Hari")
}, {
title: "Mulai - Selesai", render: (_, row) => ("13 Mei 2024 - 18 Meni 2024")
}, {
title: "Keterangan", render: (_, row) => ("Release Web")
}, {
title: "Dokumen / File", render: (_, row) => ("perjalanandinas.pdf")
}, {
render: (_, row) => {
const items = [{
key: '1', label: (<button onClick={() => modalOpen(row.divisiId, 'edit')} className="dropdown-item">
<EditOutlined className="text-muted me-2"/>Ubah
</button>),
}];
return (<>
<Dropdown trigger={['click']} placement="bottomLeft" arrow menu={{items,}}>
<button type="button" className="btn btn-circle btn-light-primary my-1" data-bs-toggle="dropdown">
<SettingOutlined/>
</button>
</Dropdown>
</>
);
}, width: "40px"
},]);
const handleSearch = (event) => {
const handler = setTimeout(() => {
setSearchText(event.target.value);
}, 1000);
return () => {
clearTimeout(handler);
};
};
const dropdownInit = async () => {
setDropdownLoading(true)
let listJabatan = await DropdownAPI.jabatan();
let listKaryawan = await DropdownAPI.karyawan();
let listJenis = await DropdownAPI.jenisPenjadwalan();
setDropdown({
jabatanId: listJabatan, karyawanId: listKaryawan, jenisId: listJenis,
})
setDropdownLoading(false)
}
const modalOpen = async (id,type) => {
setModal(prev => ({
...prev,
modalStatus: true,
jenis: type,
loadingModal: true
}));
let res = await API.GET('/ref/karyawan/'+id)
setModal(prev => ({
...prev,
data: res.result,
loadingModal: false
}));
}
useEffect(() => {
dropdownInit()
}, []);
return (<>
<WrapperContent>
<div className="containers">
<div className="headContent">
<div className="containerTitle">
<div className="breadCrumb">
<div className="text">Penjadwalan</div>
<div className="text">Penjadwalan Karyawan</div>
</div>
<div className="title text-dark-grey left">Penjadwalan Karyawan</div>
</div>
<div className="filter mb-3">
<SearchInput handleSearch={handleSearch} style={{marginRight: "10px"}}/>
<div style={{width:'300px',marginBottom:'-30px'}}>
<Input.Select title={"Jabatan"}
name={"jabatanId"}
val={watch("jabatanId")}
loading={dropdownLoading}
options={dropdown?.jabatanId}
required setValue={setValue}
register={register}
error={errors}/>
</div>
<div style={{width:'300px',marginBottom:'-30px'}}>
<Input.Select title={"Jenis"}
name={"jenisId"}
val={watch("jenisId")}
loading={dropdownLoading}
options={dropdown?.jenisId}
required setValue={setValue}
register={register}
error={errors}/>
</div>
<button type="button" className="btn btn-primary " onClick={() => modalOpen(null,'new')}>
<PlusCircleOutlined/>Tambah Penjadwalan
</button>
<button type="button" className="btn btn-circle btn-light-primary" onClick={() => getData()}>
<ReloadOutlined/>
</button>
</div>
</div>
<div className="bodyContent">
<div className={"card-table"}>
{tableColumn ? <DTAntServerSide
searchText={searchText}
endPoint={"/ref/divisi"}
triger={trigerGetData}
columnTable={tableColumn}
loadingTable={loadingTable}/> : ("loading")}
</div>
</div>
</div>
</WrapperContent>
<FormModal
loadingModal={modal?.loadingModal}
modalStatus={modal?.modalStatus}
jenis={modal?.jenis}
actClose={()=>{
setModal(prev => ({
...prev,
modalStatus: false,
loadingModal: false
}));
}}
data={modal?.data} />
</>)
}

View File

@ -0,0 +1,26 @@
.form-shift{
display: flex;
gap: 10px;
width: 100%;
background: #F4F4F4;
border-radius: 20px;
justify-content: space-between;
margin-bottom: 20px;
.title{
width: 30%;
padding: 10px 20px;
font-size: 13px;
font-weight: 600;
}
.input {
.ant-picker{
border-radius: 20px;
height: 100%;
.ant-picker-input >input {
text-align: center;
}
}
}
}

View File

@ -0,0 +1,56 @@
"use client"
import {useEffect, useState} from "react";
import RefTemplate from "@/components/refTemplate/Main";
import {Helper} from "@/lib/Helper";
export default function Page() {
const [listForm, setListForm] = useState()
const initListForm = async () => {
// TYPE form
setListForm([
{
type: 'text',
name: 'tipeQuotesNm',
alias: 'Jenis Penjadwalan',
maxLength: '150',
required: true,
col: 24
}])
}
useEffect(() => {
initListForm()
}, []);
return (
<>
<RefTemplate
refTitle="Penjadwalan"
refSubTitle="Jenis Penjadwalan"
refEndPointAll="/ref/tipeQuotes"
listAction={['create', 'update', 'delete']}
primaryKey="tipeQuotesId"
columnTableRef={[
{
title: "ID",
dataIndex: 'tipeQuotesId',
width: '10%',
sorter: (a, b) => a.tipeQuotesId - b.tipeQuotesId
},
{
title: "Jenis Penjadwalan",
dataIndex: 'tipeQuotesNm',
sorter: (a, b) => b.tipeQuotesNm.localeCompare(a.tipeQuotesNm)
},
{
title: "Update Terakhir",
render: (_, row) => (Helper.formatDate(row.uptdt,'d-M-Y H:i:s'))
},
]}
listForm={listForm}
/>
</>
)
}

View File

@ -0,0 +1,109 @@
import {useForm} from "react-hook-form";
import {useEffect, useState} from "react";
import {Col, Modal, Row, Spin} from "antd";
import {CloseOutlined} from "@ant-design/icons";
import Input from "@/components/util/Input";
import { Flex, TimePicker } from 'antd';
const { RangePicker } = TimePicker;
import dayjs from 'dayjs';
import "./style.scss";
export default function FormModal({modalStatus, actClose, data, loadingModal,jenis}) {
const [viewReadonly, setViewReadonly] = useState(false)
const format = 'HH:mm';
const {
register, setValue, watch, getValues, formState: {errors},
} = useForm();
const TypeAction = () => {
if(jenis === 'detail'){
return(
<></>
)
}else{
return(
<button className="btn btn-primary btn-sm">Simpan</button>
)
}
}
useEffect(() => {
if (jenis === 'detail'){
setViewReadonly(true);
}else{
setViewReadonly(false);
}
}, [jenis]);
return (<Modal centered closeIcon={false} open={modalStatus} width={"500px"} footer={null}>
<Spin spinning={loadingModal}>
<div className="btn btn-circle btn-light-primary zn-close" onClick={actClose}>
<CloseOutlined/>
</div>
<div className="px-6 py-4 cardDark">
<div className="fs-6 fw-bolder text-uppercase text-primary">Data Jenis Shift</div>
<div className="fs-7 fw-ligth text-muted">Data Jenis Shift</div>
<div className="separator my-3"/>
<div style={{overflowY:'auto',overflowX:'hidden',height:'600px'}} className="my-4 p-2">
<Row gutter={15}>
<Col span={24}>
<Input.Text title={"Nama Shift"} name={"karyawanNm"} minlength={"15"} maxlength={"100"} setReadonly={viewReadonly} required register={register} error={errors}/>
</Col>
<Col span={24}>
<div className={"form-shift"}>
<div className={"title"}>Senin</div>
<div className={"input"}><RangePicker placeholder={['mulai','selesai']} format={format} /></div>
</div>
</Col>
<Col span={24}>
<div className={"form-shift"}>
<div className={"title"}>Selasa</div>
<div className={"input"}><RangePicker placeholder={['mulai','selesai']} format={format} /></div>
</div>
</Col>
<Col span={24}>
<div className={"form-shift"}>
<div className={"title"}>Rabu</div>
<div className={"input"}><RangePicker placeholder={['mulai','selesai']} format={format} /></div>
</div>
</Col>
<Col span={24}>
<div className={"form-shift"}>
<div className={"title"}>Kamis</div>
<div className={"input"}><RangePicker placeholder={['mulai','selesai']} format={format} /></div>
</div>
</Col>
<Col span={24}>
<div className={"form-shift"}>
<div className={"title"}>Jum'at</div>
<div className={"input"}><RangePicker placeholder={['mulai','selesai']} format={format} /></div>
</div>
</Col>
<Col span={24}>
<div className={"form-shift"}>
<div className={"title"}>Sabtu</div>
<div className={"input"}><RangePicker placeholder={['mulai','selesai']} format={format} /></div>
</div>
</Col>
<Col span={24}>
<div className={"form-shift"}>
<div className={"title"}>Minggu</div>
<div className={"input"}><RangePicker placeholder={['mulai','selesai']} format={format} /></div>
</div>
</Col>
</Row>
</div>
</div>
<div className="card-footer text-right py-3 px-5 zn-bg-modal">
<TypeAction/>
</div>
</Spin>
</Modal>
)
}

View File

@ -1,64 +1,160 @@
"use client"
import {useEffect, useState} from "react";
import RefTemplate from "@/components/refTemplate/Main";
import {Helper} from "@/lib/Helper";
import WrapperContent from "@/components/util/WrapperContent";
import SearchInput from "@/components/util/SearchInput";
import DTAnt from "@/components/util/DTAnt";
import {API} from "@/lib/API";
import notifStore from "@/store/notifStore";
import {EditOutlined, PlusCircleOutlined, ReloadOutlined, SettingOutlined} from "@ant-design/icons";
import {Dropdown} from "antd";
import FormModal from "./FormModal";
export default function Page() {
const [listForm, setListForm] = useState()
const initListForm = async () => {
// TYPE form
setListForm([
const {notifOpen} = notifStore()
const [searchText, setSearchText] = useState(null);
const [Data, setData] = useState([]);
const [loadingTable, setLoadingTable] = useState(true)
const [modal, setModal] = useState({
loadingModal:false,
modalStatus:false,
jenis:null,
data:[]
})
const [tableColumn, setTableColumn] = useState([
{
type: 'text',
name: 'divisiNm',
alias: 'Divisi',
maxLength: '150',
required: true,
col: 24
}])
title: "Update Terakhir", render: (_, row) => (Helper.formatDate(row.uptdt, 'd-M-Y H:i:s'))
}, {
title: "Nama Shift", render: (_, row) => ("Shift Normal")
}, {
title: "Senin", render: (_, row) => ("09:00 - 17:00")
}, {
title: "Selasa", render: (_, row) => ("09:00 - 17:00")
}, {
title: "Rabu", render: (_, row) => ("09:00 - 17:00")
}, {
title: "Kamis", render: (_, row) => ("09:00 - 17:00")
}, {
title: "Jum'at", render: (_, row) => ("09:00 - 17:00")
}, {
title: "Sabtu", render: (_, row) => ("09:00 - 17:00")
}, {
title: "Minggu", render: (_, row) => ("09:00 - 17:00")
}, {
render: (_, row) => {
const items = [{
key: '1', label: (<button onClick={() => modalOpen(row.divisiId, 'edit')} className="dropdown-item">
<EditOutlined className="text-muted me-2"/>Ubah
</button>),
}];
return (<>
<Dropdown trigger={['click']} placement="bottomLeft" arrow menu={{items,}}>
<button type="button" className="btn btn-circle btn-light-primary my-1" data-bs-toggle="dropdown">
<SettingOutlined/>
</button>
</Dropdown>
</>
);
}, width: "40px"
},]);
const handleSearch = (event) => {
const handler = setTimeout(() => {
setSearchText(event.target.value);
}, 1000);
return () => {
clearTimeout(handler);
};
};
const filteredData = Data?.data?.filter((item) => Object.values(item).some((value) => {
if (searchText) {
return value?.toString().toLowerCase().includes(searchText.toLowerCase())
} else {
return value
}
}));
const getData = async () => {
setLoadingTable(true)
let response = await API.GET('/ref/divisi')
if (response.status !== 200) {
setLoadingTable(false)
notifOpen("Gagal", response?.result?.message, "danger");
return false
}
console.log(response)
setData(response?.result)
setLoadingTable(false)
}
const modalOpen = async (id,type) => {
setModal(prev => ({
...prev,
modalStatus: true,
jenis: type,
loadingModal: true
}));
let res = await API.GET('/ref/karyawan/'+id)
setModal(prev => ({
...prev,
data: res.result,
loadingModal: false
}));
}
useEffect(() => {
initListForm()
getData()
}, []);
return (
<>
<RefTemplate
refTitle="Data Karyawan"
refSubTitle="Divisi"
refEndPointAll="/ref/divisi"
listAction={['create', 'update','active', 'delete']}
primaryKey="divisiId"
columnTableRef={[
{
title: "ID",
dataIndex: 'divisiId',
width: '10%',
sorter: (a, b) => a.divisiId - b.divisiId
},
{
title: "Divisi",
dataIndex: 'divisiNm',
sorter: (a, b) => b.divisiNm.localeCompare(a.divisiNm)
},
{
title: "Update Terakhir",
render: (_, row) => (Helper.formatDate(row.uptdt,'d-M-Y H:i:s'))
},
{
title: "Status",
width: '5%',
render: (_, row) => (row.isActive === true ?
<span className="btn btn-light-success my-1 mx-1 btn-sm" style={{cursor: "none", height: "30px"}}>Aktif</span> :
<span className="btn btn-light-danger my-1 mx-1 btn-sm" style={{cursor: "none", height: "30px"}}>Tidak Aktif</span>)
},
return (<>
<WrapperContent>
<div className="containers">
<div className="headContent">
<div className="containerTitle">
<div className="breadCrumb">
<div className="text">Penjadwalan</div>
<div className="text">Penjadwalan Karyawan</div>
</div>
<div className="title text-dark-grey left">Penjadwalan Karyawan</div>
</div>
<div className="filter mb-3">
<SearchInput handleSearch={handleSearch} style={{marginRight: "10px"}}/>
<button type="button" className="btn btn-primary " onClick={() => modalOpen(null,'new')}>
<PlusCircleOutlined/>Tambah Penjadwalan
</button>
<button type="button" className="btn btn-circle btn-light-primary" onClick={() => getData()}>
<ReloadOutlined/>
</button>
</div>
</div>
]}
listForm={listForm}
/>
</>
)
<div className="bodyContent">
<div className={"card-table"}>
{tableColumn ? <DTAnt columnTable={tableColumn} data={filteredData} loadingTable={loadingTable}/> : ("loading")}
</div>
</div>
</div>
</WrapperContent>
<FormModal
loadingModal={modal?.loadingModal}
modalStatus={modal?.modalStatus}
jenis={modal?.jenis}
actClose={()=>{
setModal(prev => ({
...prev,
modalStatus: false,
loadingModal: false
}));
}}
data={modal?.data} />
</>)
}

View File

@ -0,0 +1,26 @@
.form-shift{
display: flex;
gap: 10px;
width: 100%;
background: #F4F4F4;
border-radius: 20px;
justify-content: space-between;
margin-bottom: 20px;
.title{
width: 30%;
padding: 10px 20px;
font-size: 13px;
font-weight: 600;
}
.input {
.ant-picker{
border-radius: 20px;
height: 100%;
.ant-picker-input >input {
text-align: center;
}
}
}
}

View File

@ -0,0 +1,85 @@
import {useForm} from "react-hook-form";
import {useEffect, useState} from "react";
import {Col, Modal, Row, Spin} from "antd";
import {CloseOutlined} from "@ant-design/icons";
import Input from "@/components/util/Input";
import { Flex, TimePicker } from 'antd';
const { RangePicker } = TimePicker;
import dayjs from 'dayjs';
import "./style.scss";
export default function FormModal({modalStatus, actClose, data, loadingModal,jenis}) {
const [viewReadonly, setViewReadonly] = useState(false)
const format = 'HH:mm';
const {
register, setValue, watch, getValues, formState: {errors},
} = useForm();
const TypeAction = () => {
if(jenis === 'detail'){
return(
<></>
)
}else{
return(
<button className="btn btn-primary btn-sm">Simpan</button>
)
}
}
useEffect(() => {
if (jenis === 'detail'){
setViewReadonly(true);
}else{
setViewReadonly(false);
}
setValue("karyawanNm",'Zamzam Nurzaman')
}, [jenis]);
return (<Modal centered closeIcon={false} open={modalStatus} width={"500px"} footer={null}>
<Spin spinning={loadingModal}>
<div className="btn btn-circle btn-light-primary zn-close" onClick={actClose}>
<CloseOutlined/>
</div>
<div className="px-6 py-4 cardDark">
<div className="fs-6 fw-bolder text-uppercase text-primary">Ubah Shift Karyawan Minggu Depan</div>
<div className="fs-7 fw-ligth text-muted">Ubah Shift Karyawan Minggu Depan</div>
<div className="separator my-3"/>
<div style={{overflowY:'auto',overflowX:'hidden'}} className="my-4 p-2">
<Row gutter={15}>
{(jenis === 'edit') ? <Col span={24}>
<Input.Text title={"Nama Karyawan"} name={"karyawanNm"} minlength={"15"} maxlength={"100"} setReadonly={true} required register={register} error={errors}/>
</Col>:'' }
<Col span={24}>
<Input.Select title={"Pilih Jenis Shift"} name={"roleId"} loading={false} val={watch("roleId")} setValue={setValue} options={[
{
value: 1,
label: 'Normal',
},
{
value: 2,
label: 'Pagi Malam',
}
]} required register={register} error={errors} />
</Col>
</Row>
</div>
</div>
<div className="card-footer text-right py-3 px-5 zn-bg-modal">
<TypeAction/>
</div>
</Spin>
</Modal>
)
}

View File

@ -0,0 +1,154 @@
"use client"
import {useEffect, useState} from "react";
import {Helper} from "@/lib/Helper";
import WrapperContent from "@/components/util/WrapperContent";
import SearchInput from "@/components/util/SearchInput";
import DTAnt from "@/components/util/DTAnt";
import {API} from "@/lib/API";
import notifStore from "@/store/notifStore";
import {EditOutlined, PlusCircleOutlined, ReloadOutlined, SettingOutlined} from "@ant-design/icons";
import {Dropdown} from "antd";
import FormModal from "./FormModal";
export default function Page() {
const {notifOpen} = notifStore()
const [searchText, setSearchText] = useState(null);
const [Data, setData] = useState([]);
const [loadingTable, setLoadingTable] = useState(true)
const [modal, setModal] = useState({
loadingModal:false,
modalStatus:false,
jenis:null,
data:[]
})
const [tableColumn, setTableColumn] = useState([
{
title: "Update Terakhir", render: (_, row) => (Helper.formatDate(row.uptdt, 'd-M-Y H:i:s'))
}, {
title: "Nama Karyawan", render: (_, row) => ("Zamzam Nurzaman")
}, {
title: "Jabatan", render: (_, row) => ("Staf Lapangan")
}, {
title: "Status Pegawai", render: (_, row) => ("Pegawai Tetap")
}, {
title: "Shift Minggu Ini", render: (_, row) => ("Shift Normal")
}, {
title: "Shift Minggu Depan", render: (_, row) => ("Pagi Malam")
}, {
render: (_, row) => {
const items = [{
key: '1', label: (<button onClick={() => modalOpen(row.divisiId, 'edit')} className="dropdown-item">
<EditOutlined className="text-muted me-2"/>Ubah
</button>),
}];
return (<>
<Dropdown trigger={['click']} placement="bottomLeft" arrow menu={{items,}}>
<button type="button" className="btn btn-circle btn-light-primary my-1" data-bs-toggle="dropdown">
<SettingOutlined/>
</button>
</Dropdown>
</>
);
}, width: "40px"
},]);
const handleSearch = (event) => {
const handler = setTimeout(() => {
setSearchText(event.target.value);
}, 1000);
return () => {
clearTimeout(handler);
};
};
const filteredData = Data?.data?.filter((item) => Object.values(item).some((value) => {
if (searchText) {
return value?.toString().toLowerCase().includes(searchText.toLowerCase())
} else {
return value
}
}));
const getData = async () => {
setLoadingTable(true)
let response = await API.GET('/ref/divisi')
if (response.status !== 200) {
setLoadingTable(false)
notifOpen("Gagal", response?.result?.message, "danger");
return false
}
console.log(response)
setData(response?.result)
setLoadingTable(false)
}
const modalOpen = async (id,type) => {
setModal(prev => ({
...prev,
modalStatus: true,
jenis: type,
loadingModal: true
}));
let res = await API.GET('/ref/karyawan/'+id)
setModal(prev => ({
...prev,
data: res.result,
loadingModal: false
}));
}
useEffect(() => {
getData()
}, []);
return (<>
<WrapperContent>
<div className="containers">
<div className="headContent">
<div className="containerTitle">
<div className="breadCrumb">
<div className="text">Shift</div>
<div className="text">Daftar Shift Karyawan</div>
</div>
<div className="title text-dark-grey left">Daftar Shift Karyawan</div>
</div>
<div className="filter mb-3">
<SearchInput handleSearch={handleSearch} style={{marginRight: "10px"}}/>
<button type="button" className="btn btn-primary " onClick={() => modalOpen(null,'semua')}>
<PlusCircleOutlined/>Ubah Semua Shift karyawan
</button>
<button type="button" className="btn btn-circle btn-light-primary" onClick={() => getData()}>
<ReloadOutlined/>
</button>
</div>
</div>
<div className="bodyContent">
<div className={"card-table"}>
{tableColumn ? <DTAnt columnTable={tableColumn} data={filteredData} loadingTable={loadingTable}/> : ("loading")}
</div>
</div>
</div>
</WrapperContent>
<FormModal
loadingModal={modal?.loadingModal}
modalStatus={modal?.modalStatus}
jenis={modal?.jenis}
actClose={()=>{
setModal(prev => ({
...prev,
modalStatus: false,
loadingModal: false
}));
}}
data={modal?.data} />
</>)
}

View File

@ -1,79 +0,0 @@
"use client";
import Head from "next/head";
import * as Sentry from "@sentry/nextjs";
export default function Page() {
return (
<div>
<Head>
<title>Sentry Onboarding</title>
<meta name="description" content="Test Sentry for your Next.js app!" />
</Head>
<main
style={{
minHeight: "100vh",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
}}
>
<h1 style={{ fontSize: "4rem", margin: "14px 0" }}>
<svg
style={{
height: "1em",
}}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 200 44"
>
<path
fill="currentColor"
d="M124.32,28.28,109.56,9.22h-3.68V34.77h3.73V15.19l15.18,19.58h3.26V9.22h-3.73ZM87.15,23.54h13.23V20.22H87.14V12.53h14.93V9.21H83.34V34.77h18.92V31.45H87.14ZM71.59,20.3h0C66.44,19.06,65,18.08,65,15.7c0-2.14,1.89-3.59,4.71-3.59a12.06,12.06,0,0,1,7.07,2.55l2-2.83a14.1,14.1,0,0,0-9-3c-5.06,0-8.59,3-8.59,7.27,0,4.6,3,6.19,8.46,7.52C74.51,24.74,76,25.78,76,28.11s-2,3.77-5.09,3.77a12.34,12.34,0,0,1-8.3-3.26l-2.25,2.69a15.94,15.94,0,0,0,10.42,3.85c5.48,0,9-2.95,9-7.51C79.75,23.79,77.47,21.72,71.59,20.3ZM195.7,9.22l-7.69,12-7.64-12h-4.46L186,24.67V34.78h3.84V24.55L200,9.22Zm-64.63,3.46h8.37v22.1h3.84V12.68h8.37V9.22H131.08ZM169.41,24.8c3.86-1.07,6-3.77,6-7.63,0-4.91-3.59-8-9.38-8H154.67V34.76h3.8V25.58h6.45l6.48,9.2h4.44l-7-9.82Zm-10.95-2.5V12.6h7.17c3.74,0,5.88,1.77,5.88,4.84s-2.29,4.86-5.84,4.86Z M29,2.26a4.67,4.67,0,0,0-8,0L14.42,13.53A32.21,32.21,0,0,1,32.17,40.19H27.55A27.68,27.68,0,0,0,12.09,17.47L6,28a15.92,15.92,0,0,1,9.23,12.17H4.62A.76.76,0,0,1,4,39.06l2.94-5a10.74,10.74,0,0,0-3.36-1.9l-2.91,5a4.54,4.54,0,0,0,1.69,6.24A4.66,4.66,0,0,0,4.62,44H19.15a19.4,19.4,0,0,0-8-17.31l2.31-4A23.87,23.87,0,0,1,23.76,44H36.07a35.88,35.88,0,0,0-16.41-31.8l4.67-8a.77.77,0,0,1,1.05-.27c.53.29,20.29,34.77,20.66,35.17a.76.76,0,0,1-.68,1.13H40.6q.09,1.91,0,3.81h4.78A4.59,4.59,0,0,0,50,39.43a4.49,4.49,0,0,0-.62-2.28Z"
></path>
</svg>
</h1>
<p>Get started by sending us a sample error:</p>
<button
type="button"
style={{
padding: "12px",
cursor: "pointer",
backgroundColor: "#AD6CAA",
borderRadius: "4px",
border: "none",
color: "white",
fontSize: "14px",
margin: "18px",
}}
onClick={async () => {
await Sentry.startSpan({
name: 'Example Frontend Span',
op: 'test'
}, async () => {
const res = await fetch("/api/sentry-example-api");
if (!res.ok) {
throw new Error("Sentry Example Frontend Error");
}
});
}}
>
Throw error!
</button>
<p>
Next, look for the error on the{" "}
<a href="https://basys-zl.sentry.io/issues/?project=4507818838654976">Issues Page</a>.
</p>
<p style={{ marginTop: "24px" }}>
For more information, see{" "}
<a href="https://docs.sentry.io/platforms/javascript/guides/nextjs/">
https://docs.sentry.io/platforms/javascript/guides/nextjs/
</a>
</p>
</main>
</div>
);
}

View File

@ -2,6 +2,7 @@ import React, {useEffect, useState} from "react";
import {Table} from "antd";
import LoadingTable from "@/components/util/LoadingTable";
import {v4 as uuidv4} from "uuid";
function DTAnt({ columnTable, data, loadingTable, size, pageSize, rowKey, totalRow }) {
const [columns, setColumns] = useState([]);
@ -20,7 +21,7 @@ function DTAnt({ columnTable, data, loadingTable, size, pageSize, rowKey, totalR
locale={{ emptyText: (loadingTable) ? '-' : null }}
columns={columns}
dataSource={data}
rowKey={rowKey}
rowKey={() => (rowKey) ? rowKey: uuidv4()}
size={(size) ? size : 'medium'}
pagination={{
defaultPageSize: (pageSize) ? pageSize : 10,

View File

@ -11,6 +11,7 @@ const InputSelect = ({
setValue,
setReadonly,
setDisabled,
setMultiple,
val,
loading,
withSearch = true,
@ -39,7 +40,8 @@ const InputSelect = ({
<Select
disabled={setReadonly || setDisabled}
// defaultValue="lucy"
mode={(setMultiple) ? 'multiple':false}
{...register(name, validateList)}
name={name}
showSearch={withSearch}

View File

@ -65,6 +65,25 @@ const statusKaryawan = async () => {
});
}
const karyawan = async () => {
let response = await API.GET(`/ref/karyawan`);
return response?.result?.data?.map((v) => {
return {
value: v.karyawanId,
label: v.karyawanNm,
};
});
}
const jenisPenjadwalan = async () => {
let response = await API.GET(`/ref/tipeQuotes`);
return response?.result?.data?.map((v) => {
return {
value: v.tipeQuotesId,
label: v.tipeQuotesNm,
};
});
}
export const DropdownAPI = {
role,
cabang,
@ -72,5 +91,7 @@ export const DropdownAPI = {
agama,
jabatan,
jenisKelamin,
statusKaryawan
statusKaryawan,
karyawan,
jenisPenjadwalan
};