diff --git a/src/const/ApiConst.js b/src/const/ApiConst.js index d7bdf1a..f8ef23b 100644 --- a/src/const/ApiConst.js +++ b/src/const/ApiConst.js @@ -806,3 +806,18 @@ export const MENU_COMPANY_EDIT = (id) => { export const MENU_COMPANY_DELETE = (id) => { return `${BASE_SIMPRO_LUMEN}/menu-company/delete/${id}`; }; + + + +export const DEMO_MANAGEMENT_ADD = `${BASE_SIMPRO_LUMEN}/demo-management/add`; +export const DEMO_MANAGEMENT_SEARCH = `${BASE_SIMPRO_LUMEN}/demo-management/search`; +export const DEMO_MANAGEMENT_EDIT = (id) => { + return `${BASE_SIMPRO_LUMEN}/demo-management/update/${id}`; +}; +export const DEMO_MANAGEMENT_GET_ID = (id) => { + return `${BASE_SIMPRO_LUMEN}/demo-management/edit/${id}`; +}; +export const DEMO_MANAGEMENT_DELETE = (id) => { + return `${BASE_SIMPRO_LUMEN}/demo-management/delete/${id}`; +}; +export const DEMO_MANAGEMENT_LIST = `${BASE_SIMPRO_LUMEN}/demo-management/list`; diff --git a/src/const/en.json b/src/const/en.json index 07b20a3..4a06ec8 100644 --- a/src/const/en.json +++ b/src/const/en.json @@ -34,6 +34,7 @@ "description": "Description", "division": "Division", "divisionAdd": "Add Division", + "demoAdd": "Add Demo", "employeeType": "Employee Type", "edit": "Edit", "export": "Export", @@ -66,6 +67,8 @@ "inputEmail": "Input Email", "inputNoPhone": "Input Phone Number", "inputNik": "Input NIK (KTP)", + "inputMessage": "Input Message", + "inputRole": "Input Role", "image": "Image", "imageCheck": "Selfie Presence", "locIn": "Location In", @@ -100,6 +103,7 @@ "presenceIn": "Presence In", "presenceOut": "Presence Out", "panicButton": "Panic Button", + "phoneNumber": "Phone Number", "price": "Price", "qty": "QTY", "qtyReceived": "QTY Received", @@ -114,6 +118,7 @@ "search": "Search", "save": "Save", "saveSend": "Save & Send", + "searchDemo": "Search Data Demo", "searchType": "Search Project Type", "searchPhase": "Search Project Phase", "searchDivision": "Search Division", diff --git a/src/const/id.json b/src/const/id.json index 92b395a..4d25734 100644 --- a/src/const/id.json +++ b/src/const/id.json @@ -34,6 +34,7 @@ "description": "Deskripsi", "division": "Divisi", "divisionAdd": "Tambah Divisi", + "demoAdd": "Tambah Demo", "edit": "Ubah", "export": "Ekspor", "exportExcel": "Ekspor Excel", @@ -66,6 +67,8 @@ "inputEmail": "Masukan Email", "inputNoPhone": "Masukan No Telp", "inputNik": "Masukan NIK (KTP)", + "inputMessage": "Masukan Pesan", + "inputRole": "Masukan Peran", "image": "Gambar", "imageCheck": "Lihat Selfie Presensi", "locIn": "Lokasi Masuk", @@ -100,6 +103,7 @@ "presenceIn": "Waktu Masuk", "presenceOut": "Waktu Pulang", "panicButton": "Tombol Panik", + "phoneNumber": "No Telepon", "price": "Harga", "qty": "Kuantitas", "qtyReceived": "Kuantitas Diterima", @@ -116,6 +120,7 @@ "search": "Cari", "searchType": "Cari Tipe Proyek", "searchPhase": "Cari Fase Proyek", + "searchDemo": "Cari Data Demo", "searchDivision": "Cari Divisi", "searchUom": "Cari Satuan", "searchChecklistK3": "Cari Ceklis K3", diff --git a/src/routes.js b/src/routes.js index ac74528..6847782 100644 --- a/src/routes.js +++ b/src/routes.js @@ -55,11 +55,12 @@ const DashboardProjectCarousell = React.lazy(() => import('./views/Dashboard/Das const MapMonitoring = React.lazy(() => import('./views/MapMonitoring')); const Settings = React.lazy(() => import('./views/SimproV2/Settings')); const CompanyManagement = React.lazy(() => import('./views/Master/MasterCompany')) +const DemoManagement = React.lazy(() => import('./views/SimproV2/Demo')) const routes = [ { path: '/', exact: true, name: 'Home' }, { path: '/dashboard', name: 'DashboardBOD', component: DashboardBOD }, { path: '/dashboard-customer/:PROJECT_ID/:GANTT_ID/:SCURVE', name: 'DashboardCustomer', component: DashboardCustomer }, - { path: '/dashboard-project/:PROJECT_ID/:GANTT_ID', exact: true, name: 'Dashboard Project', component: DashboardProject }, + { path: '/dashboard-project/:PROJECT_ID/:GANTT_ID/:Header', exact: true, name: 'Dashboard Project', component: DashboardProject }, { path: '/dashboard-perproject', exact: true, name: 'Dashboard Project Carousell', component: DashboardProjectCarousell }, { path: '/dashboard-project/:PROJECT_ID/:GANTT_ID/:SCURVE', exact: true, name: 'Dashboard Project', component: DashboardProject }, { path: '/projects', exact: true, name: 'Projects', component: CreatedProyek }, @@ -119,6 +120,7 @@ const routes = [ // { path: '/dashboard-project/:ID/:GANTTID', exact: true, name: 'Dashboard Project', component: DashboardProject }, { path: '/settings', exact: true, name: 'Settings', component: Settings }, { path: '/company-management', exact: true, name: 'Company Management', component: CompanyManagement }, + { path: '/demo-management', exact: true, name: 'Demo Management', component: DemoManagement }, ]; export default routes; diff --git a/src/views/SimproV2/Demo/DialogForm.js b/src/views/SimproV2/Demo/DialogForm.js new file mode 100644 index 0000000..9abe0b6 --- /dev/null +++ b/src/views/SimproV2/Demo/DialogForm.js @@ -0,0 +1,180 @@ +import React, { useEffect, useState } from 'react' +import { + Modal, ModalHeader, ModalBody, ModalFooter, + Button, Form, FormGroup, Label, Input, Col, Row +} from 'reactstrap'; +import { Select } from 'antd'; +import 'antd/dist/antd.css'; +import { useTranslation } from 'react-i18next'; +import "rc-color-picker/assets/index.css"; +const { Option } = Select +const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdit }) => { + const [id, setId] = useState(0) + const [name, setName] = useState('') + const [email, setEmail] = useState('') + const [message, setMessage] = useState('') + const [phoneNumber, setPhoneNumber] = useState('') + const [role, setRole] = useState(null) + const [status, setStatus] = useState('') + const { t } = useTranslation() + + useEffect(() => { + if (typeDialog === "Edit") { + setId(dataEdit.id) + } else { + setId(0) + + } + }, [dataEdit, openDialog]) + + const validation = () => { + if (!name || name === "") { + alert("Name cannot be empty!"); + return true; + } + } + const handleSave = () => { + let data = ''; + const err = validation(); + + if (!err) { + if (typeDialog === "Save") { + data = { + name + } + closeDialog('save', data); + } else { + data = { + id, + name, + } + closeDialog('edit', data); + } + setId(0) + setName('') + } + } + const handleCancel = () => { + closeDialog('cancel', 'none') + setId(0) + setName('') + } + const onChangeStatus = (val) => { + setStatus(val) + } + + + const renderForm = () => { + return ( +
+ + + * Wajib diisi. + + + + + + + setName(e.target.value)} + placeholder={t('inputName')} + /> + + + + + + setEmail(e.target.value)} + placeholder={t('inputEmail')} + /> + + + + + + + + setName(e.target.value)} + placeholder={t('inputNoPhone')} + /> + + + + + + setRole(e.target.value)} + placeholder={t('inputRole')} + /> + + + + + + + + + + + + + + + + setMessage(e.target.value)} placeholder={t('inputMessage')} /> + + + +
+ ) + } + + + return ( + <> + + {typeDialog == "Save" ? `Add` : "Edit"} {t('Demo')} + + {renderForm()} + + + {' '} + + + + + ) + +} + +export default DialogForm; diff --git a/src/views/SimproV2/Demo/index.js b/src/views/SimproV2/Demo/index.js new file mode 100644 index 0000000..a3fc1fa --- /dev/null +++ b/src/views/SimproV2/Demo/index.js @@ -0,0 +1,367 @@ +import * as XLSX from 'xlsx'; +import DialogForm from './DialogForm'; +import React, { useState, useEffect } from 'react'; +import SweetAlert from 'react-bootstrap-sweetalert'; +import axios from "../../../const/interceptorApi" +import { Card, CardBody, CardHeader, Col, Row, Input, Table } from 'reactstrap'; +import { DEMO_MANAGEMENT_EDIT, DEMO_MANAGEMENT_SEARCH, DEMO_MANAGEMENT_LIST, DEMO_MANAGEMENT_GET_ID, DEMO_MANAGEMENT_ADD, DEMO_MANAGEMENT_DELETE } from '../../../const/ApiConst'; +import { NotificationContainer, NotificationManager } from 'react-notifications'; +import { Pagination, Button, Tooltip } from 'antd'; +import { useTranslation } from 'react-i18next'; + + +const ProjectType = ({ params, ...props }) => { + let role_id = 0, user_id = 0, isLogin = false, token = '', company_id = 0, all_project = null, role_name = '', hierarchy = [], user_name = ''; + if (props && props.role_id && props.user_id) { + role_id = props.role_id; + user_id = props.user_id; + token = props.token; + isLogin = props.isLogin; + company_id = props.company_id; + all_project = props.all_project; + role_name = props.role_name; + isLogin = props.isLogin; + hierarchy = props.hierarchy; + user_name = props.user_name; + } + + const HEADER = { + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${token}` + } + } + const pageName = params.name; + + const [alertDelete, setAlertDelete] = useState(false) + const [allDataMenu, setAllDataMenu] = useState([]) + const [clickOpenModal, setClickOpenModal] = useState(false) + const [currentPage, setCurrentPage] = useState(1) + const [dataEdit, setDataEdit] = useState([]) + const [dataExport, setDataExport] = useState([]) + const [dataTable, setDatatable] = useState([]) + const [idDelete, setIdDelete] = useState(0) + const [openDialog, setOpenDialog] = useState(false) + const [rowsPerPage, setRowsPerPage] = useState(10) + const [search, setSearch] = useState("") + const [totalPage, setTotalPage] = useState(0) + const [typeDialog, setTypeDialog] = useState('Save') + const [dataDemo, setDataDemo] = useState([]) + const [listCompany, setListCompany] = useState([]) + const { t } = useTranslation() + const column = [ + { name: t('name') }, + { name: t('email') }, + { name: t('roles') }, + { name: t('phoneNumber') }, + { name: t('status') }, + { name: t('message') }, + ].filter(column => column && column.name); + useEffect(() => { + getDataDemo(); + }, [currentPage, rowsPerPage, search]) + + useEffect(() => { + const cekData = dataExport || [] + if (cekData.length > 0) { + exportExcel() + } + }, [dataExport]) + + const getDataDemo = async () => { + let start = 0; + if (currentPage !== 1 && currentPage > 1) { + start = currentPage * rowsPerPage - rowsPerPage; + } + const payload = { + group_column: { + "operator": "AND", + "group_operator": "OR", + "where": [ + { + "name": "name", + "logic_operator": "~*", + "value": search, + } + ] + }, + columns: [], + "orders": { + "ascending": true, + "columns": [ + 'id' + ] + }, + "paging": { + "length": rowsPerPage, + "start": start + }, + 'joins': [] + } + + const result = await axios + .post(DEMO_MANAGEMENT_SEARCH, payload, HEADER) + .then(res => res) + .catch((error) => error.response); + + if (result && result.data && result.data.code == 200) { + setDatatable(result.data.data); + setTotalPage(result.data.totalRecord); + } else { + NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); + } + } + const handleExportExcel = async () => { + let start = 0; + + if (currentPage !== 1 && currentPage > 1) { + start = (currentPage * rowsPerPage) - rowsPerPage + } + + const payload = { + group_column: { + "operator": "AND", + "group_operator": "OR", + "where": [ + { + "name": "name", + "logic_operator": "~*", + "value": search, + } + ] + }, + "columns": [], + "orders": { + "ascending": true, + "columns": [ + 'id' + ] + }, + "paging": { + "length": rowsPerPage, + "start": start + }, + 'joins': [] + } + + const result = await axios + .post(DEMO_MANAGEMENT_SEARCH, payload, HEADER) + .then(res => res) + .catch((error) => error.response); + if (result && result.data && result.data.code == 200) { + let resData = result.data.data; + const excelData = []; + resData.map((val, index) => { + let dataRow = {}; + dataRow["Nama"] = val.name; + dataRow["Email"] = val.email; + dataRow["Role"] = val.role; + dataRow["No Telepon"] = val.number_phone; + dataRow["Status"] = val.message; + dataRow["Message"] = val.message; + excelData.push(dataRow) + }) + await setDataExport(excelData) + } else { + NotificationManager.error('Gagal Export Data!!', 'Failed'); + } + } + + const exportExcel = () => { + const dataExcel = dataExport || []; + const fileName = `Data ${pageName}.xlsx`; + const ws = XLSX.utils.json_to_sheet(dataExcel); + const wb = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`); + XLSX.writeFile(wb, fileName); + setDataExport([]) + } + + const handleSearch = e => { + const value = e.target.value + setSearch(value); + setCurrentPage(1) + }; + + const handleOpenDialog = (type) => { + setOpenDialog(true) + setTypeDialog(type) + } + + const handleEdit = (data) => { + setDataEdit(data) + handleOpenDialog('Edit'); + } + + const handleDelete = async (id) => { + await setAlertDelete(true) + await setIdDelete(id) + } + + const handleCloseDialog = (type, data) => { + if (type === "save") { + saveDemo(data); + } else if (type === "edit") { + editMaterialR(data); + } + setDataEdit([]) + setOpenDialog(false) + } + + const saveDemo = async (data) => { + const formData = data + const result = await axios.post(DEMO_MANAGEMENT_ADD, formData, HEADER) + .then(res => res) + .catch((error) => error.response); + if (result && result.data && result.data.code === 200) { + getDataDemo() + NotificationManager.success(`Data berhasil ditambahkan`, 'Success!!'); + } else { + NotificationManager.error(`Data gagal ditambahkan`, 'Failed!!'); + } + } + + const editMaterialR = async (data) => { + let urlEdit = DEMO_MANAGEMENT_EDIT(data.id) + const formData = data + const result = await axios.put(urlEdit, formData, HEADER) + .then(res => res) + .catch((error) => error.response); + if (result && result.data && result.data.code === 200) { + getDataDemo(); + NotificationManager.success(`Data berhasil diubah`, 'Success!!'); + } else { + NotificationManager.error(`Data gagal diubah`, `Failed!!`); + } + } + + const toggleAddDialog = () => { + setOpenDialog(!openDialog) + } + + const onConfirmDelete = async () => { + let url = DEMO_MANAGEMENT_DELETE(idDelete); + const result = await axios.delete(url, HEADER) + .then(res => res) + .catch((error) => error.response); + + if (result && result.data && result.data.code === 200) { + getDataDemo() + setIdDelete(0) + setAlertDelete(false) + NotificationManager.success(`Data berhasil dihapus!`, 'Success!!'); + } else { + setIdDelete(0) + setAlertDelete(false) + NotificationManager.error(`Data gagal dihapus!}`, 'Failed!!'); + } + } + + const cancelDelete = () => { + setAlertDelete(false) + setIdDelete(0) + } + + const onShowSizeChange = (current, pageSize) => { + setRowsPerPage(pageSize) + } + + const onPagination = (current, pageSize) => { + setCurrentPage(current) + } + + const dataNotAvailable = () => { + if (dataTable.length === 0) { + return ( + + {t('noData')} + + ) + } + } + + return ( +
+ + + {t('deleteMsg')} + + toggleAddDialog} + typeDialog={typeDialog} + dataEdit={dataEdit} + clickOpenModal={clickOpenModal} + dataParent={allDataMenu} + /> + + +

{pageName}

+ + + + + + + + + + + + + +
+ + + + + + {column.map((i, index) => { + return ( + + ) + })} + + + + {dataNotAvailable()} + {dataTable.map((n, index) => { + return ( + + + + + + + + + + ) + })} + +
Aksi{i.name}
+ + handleDelete(n.id)}> + + + handleEdit(n)}> + + {n.name}{n.email}{n.role}{n.number_phone}{n.status}{n.message}
+
+
+
+ ) +} + +export default ProjectType;