farhantock
1 year ago
35 changed files with 5822 additions and 171 deletions
@ -1,20 +1,22 @@ |
|||||||
FROM node:12 |
# Stage 1 |
||||||
|
FROM node:14 as build-stage |
||||||
|
|
||||||
WORKDIR /react-docker |
WORKDIR /react-docker |
||||||
COPY ./package*.json ./ |
COPY package.json . |
||||||
ENV PATH /app/node_modules/.bin:$PATH |
|
||||||
RUN npm install |
RUN npm install |
||||||
RUN npm i react@16.14.0 |
COPY . . |
||||||
RUN npm i react-scripts |
|
||||||
RUN npm audit fix |
#ARG REACT_APP_API_BASE_URL |
||||||
|
#ENV REACT_APP_API_BASE_URL=$REACT_APP_API_BASE_URL |
||||||
|
|
||||||
EXPOSE 8445 |
RUN npm run build |
||||||
|
|
||||||
# Comment as needed (Production / Dev) |
# Stage 2 |
||||||
# [PROD] Use for Production |
#FROM nginx:1.17.0-alpine |
||||||
# COPY . . # uncomment prod |
FROM nginx:alpine |
||||||
|
|
||||||
# [DEV] Live Reload |
COPY --from=build-stage /react-docker/build /usr/share/nginx/html |
||||||
RUN mkdir -p /react-docker/src # comment for prod |
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf |
||||||
RUN mkdir -p /react-docker/public # comment for prod |
EXPOSE 80 |
||||||
|
|
||||||
CMD PORT=8445 npm start #--host 0.0.0.0 --port 3000 --disableHostCheck true |
CMD nginx -g 'daemon off;' |
||||||
|
@ -0,0 +1,17 @@ |
|||||||
|
server { |
||||||
|
|
||||||
|
listen 80; |
||||||
|
|
||||||
|
location / { |
||||||
|
root /usr/share/nginx/html; |
||||||
|
index index.html index.htm; |
||||||
|
try_files $uri $uri/ /index.html; |
||||||
|
} |
||||||
|
|
||||||
|
error_page 500 502 503 504 /50x.html; |
||||||
|
|
||||||
|
location = /50x.html { |
||||||
|
root /usr/share/nginx/html; |
||||||
|
} |
||||||
|
|
||||||
|
} |
After Width: | Height: | Size: 54 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,822 @@ |
|||||||
|
import React, { useState, useMemo, useEffect } from 'react' |
||||||
|
import { |
||||||
|
Modal, ModalHeader, ModalBody, ModalFooter, |
||||||
|
Button, Form, FormGroup, Row, Col, Label, Input, |
||||||
|
} from 'reactstrap'; |
||||||
|
import { Pagination, Table, Tooltip, Select } from 'antd'; |
||||||
|
import SweetAlert from 'react-bootstrap-sweetalert'; |
||||||
|
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||||
|
import DialogFormUser from './FormUser'; |
||||||
|
import DialogFormMenu from './FormMenu'; |
||||||
|
import 'antd/dist/antd.css'; |
||||||
|
import { useTranslation } from 'react-i18next'; |
||||||
|
import axios from "../../../const/interceptorApi" |
||||||
|
import { |
||||||
|
USER_SEARCH, USER_EDIT, USER_DELETE, ROLE_SEARCH, DIVISI_SEARCH, MENU_COMPANY_SEARCH |
||||||
|
} from '../../../const/ApiConst'; |
||||||
|
const token = window.localStorage.getItem('token'); |
||||||
|
const config = { |
||||||
|
headers: |
||||||
|
{ |
||||||
|
Authorization: `Bearer ${token}`, |
||||||
|
"Content-type": `application/json` |
||||||
|
} |
||||||
|
}; |
||||||
|
const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, companyID, companyNameProp }) => { |
||||||
|
const { Option } = Select |
||||||
|
const { t } = useTranslation() |
||||||
|
const [registrationnumber, setRegistrationNumber] = useState('') |
||||||
|
const [companyName, setCompanyName] = useState('') |
||||||
|
const [addressCompany, setAddressCompany] = useState('') |
||||||
|
const [phoneNumber, setPhoneNumber] = useState('') |
||||||
|
const [emailCompany, setEmailCompany] = useState('') |
||||||
|
const [description, setDescription] = useState('') |
||||||
|
const [logoLogin, setLogoLogin] = useState([]) |
||||||
|
const [logoHeader, setLogoHeader] = useState([]) |
||||||
|
const [favIcon, setFavIcon] = useState([]) |
||||||
|
const [loginInstruction, setLoginInstruction] = useState('') |
||||||
|
const [about, setAbout] = useState('') |
||||||
|
const [htmlTitle, setHtmlTitle] = useState('') |
||||||
|
const [appName, setAppName] = useState('') |
||||||
|
const [baseUrl, setBaseUrl] = useState([]) |
||||||
|
const [statusCompany, setStatusCompany] = useState(true) |
||||||
|
const [template, setTemplate] = useState('') |
||||||
|
const [lastIdxURL, setLastIdxURL] = useState(0); |
||||||
|
|
||||||
|
|
||||||
|
const [dataTable, setDatatable] = useState([]) |
||||||
|
const [openDialogUser, setOpenDialogUser] = useState(false) |
||||||
|
const [typeDialogUser, setTypeDialogUser] = useState("add") |
||||||
|
const [currentPage, setCurrentPage] = useState(1) |
||||||
|
const [rowsPerPage, setRowsPerPage] = useState(10) |
||||||
|
const [totalPage, setTotalPage] = useState(0) |
||||||
|
const [search, setSearch] = useState('') |
||||||
|
const [idDelete, setIdDelete] = useState(0) |
||||||
|
const [alertDelete, setAlertDelete] = useState(false) |
||||||
|
const [dataEdit, setDataEdit] = useState([]) |
||||||
|
const [roleList, setRoleList] = useState([]) |
||||||
|
|
||||||
|
|
||||||
|
const [dataTableMenu, setDatatableMenu] = useState([]) |
||||||
|
const [currentPageMenu, setCurrentPageMenu] = useState(1) |
||||||
|
const [rowsPerPageMenu, setRowsPerPageMenu] = useState(10) |
||||||
|
const [totalPageMenu, setTotalPageMenu] = useState(0) |
||||||
|
const [openDialogMenu, setOpenDialogMenu] = useState(false) |
||||||
|
const [typeDialogMenu, setTypeDialogMenu] = useState("add") |
||||||
|
useEffect(() => { |
||||||
|
if (companyID && typeDialog === 'Set') { |
||||||
|
getDataUser() |
||||||
|
getRoleList() |
||||||
|
} else { |
||||||
|
getDataMenu() |
||||||
|
} |
||||||
|
}, [typeDialog, companyID, rowsPerPage, currentPage, rowsPerPageMenu, currentPageMenu]) |
||||||
|
|
||||||
|
|
||||||
|
const onShowSizeChange = (current, pageSize) => { |
||||||
|
setRowsPerPage(pageSize) |
||||||
|
} |
||||||
|
|
||||||
|
const onPagination = (current, pageSize) => { |
||||||
|
setCurrentPage(current) |
||||||
|
} |
||||||
|
const onShowSizeChangeMenu = (current, pageSize) => { |
||||||
|
setRowsPerPageMenu(pageSize) |
||||||
|
} |
||||||
|
|
||||||
|
const onPaginationMenu = (current, pageSize) => { |
||||||
|
setCurrentPageMenu(current) |
||||||
|
} |
||||||
|
|
||||||
|
const getRoleList = async () => { |
||||||
|
const formData = { |
||||||
|
"paging": { "start": 0, "length": -1 }, |
||||||
|
|
||||||
|
"orders": { "columns": ["id"], "ascending": false } |
||||||
|
} |
||||||
|
|
||||||
|
const result = await axios |
||||||
|
.post(ROLE_SEARCH, formData, config) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code == 200) { |
||||||
|
setRoleList(result.data.data); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const getDataUser = async () => { |
||||||
|
let start = 0; |
||||||
|
|
||||||
|
if (currentPage !== 1 && currentPage > 1) { |
||||||
|
start = (currentPage * rowsPerPage) - rowsPerPage |
||||||
|
} |
||||||
|
|
||||||
|
const payload = { |
||||||
|
"paging": { |
||||||
|
"start": start, |
||||||
|
"length": rowsPerPage |
||||||
|
}, |
||||||
|
"columns": [], |
||||||
|
"group_column": { |
||||||
|
"operator": "AND", |
||||||
|
"group_operator": "OR", |
||||||
|
"where": [ |
||||||
|
{ |
||||||
|
"name": "name", |
||||||
|
"logic_operator": "~*", |
||||||
|
"value": search |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "ktp_number", |
||||||
|
"logic_operator": "~*", |
||||||
|
"value": search |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "name", |
||||||
|
"logic_operator": "~*", |
||||||
|
"value": search, |
||||||
|
"table_name": "m_divisi" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "employee_type", |
||||||
|
"logic_operator": "~*", |
||||||
|
"value": search |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "name", |
||||||
|
"logic_operator": "~*", |
||||||
|
"value": search, |
||||||
|
"table_name": "m_roles" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "phone_number", |
||||||
|
"logic_operator": "~*", |
||||||
|
"value": search |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "email", |
||||||
|
"logic_operator": "~*", |
||||||
|
"value": search |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "status_resource", |
||||||
|
"logic_operator": "~*", |
||||||
|
"value": search |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "company_id", |
||||||
|
"logic_operator": "=", |
||||||
|
"value": companyID |
||||||
|
}, |
||||||
|
] |
||||||
|
}, |
||||||
|
"joins": [ |
||||||
|
{ |
||||||
|
"name": "m_roles", |
||||||
|
"column_join": "role_id", |
||||||
|
"column_results": [ |
||||||
|
"name", |
||||||
|
"description" |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "m_divisi", |
||||||
|
"column_join": "divisi_id", |
||||||
|
"column_results": [ |
||||||
|
"name" |
||||||
|
] |
||||||
|
} |
||||||
|
], |
||||||
|
"orders": { |
||||||
|
"columns": [ |
||||||
|
"id" |
||||||
|
], |
||||||
|
"ascending": false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const result = await axios |
||||||
|
.post(USER_SEARCH, payload, config) |
||||||
|
.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 getDataMenu = async () => { |
||||||
|
let start = 0; |
||||||
|
|
||||||
|
if (currentPage !== 1 && currentPage > 1) { |
||||||
|
start = (currentPage * rowsPerPage) - rowsPerPage |
||||||
|
} |
||||||
|
|
||||||
|
const payload = { |
||||||
|
"paging": { |
||||||
|
"start": start, |
||||||
|
"length": rowsPerPage |
||||||
|
}, |
||||||
|
"columns": [{ |
||||||
|
"name": "company_id", |
||||||
|
"logic_operator": "=", |
||||||
|
"value": companyID, |
||||||
|
"operator": "AND" |
||||||
|
}], |
||||||
|
"joins": [{ |
||||||
|
"name": "m_menu", |
||||||
|
"column_join": "menu_id", |
||||||
|
"column_results": [ |
||||||
|
"name" |
||||||
|
] |
||||||
|
}], |
||||||
|
"orders": { "columns": ["id"], "ascending": false } |
||||||
|
} |
||||||
|
|
||||||
|
const result = await axios |
||||||
|
.post(MENU_COMPANY_SEARCH, payload, config) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code == 200) { |
||||||
|
setDatatableMenu(result.data.data); |
||||||
|
setTotalPageMenu(result.data.totalRecord); |
||||||
|
} else { |
||||||
|
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const handleAddUser = async () => { |
||||||
|
await setTypeDialogUser("Save") |
||||||
|
setOpenDialogUser(true) |
||||||
|
} |
||||||
|
|
||||||
|
const handleEditUser = async (data) => { |
||||||
|
setDataEdit(data) |
||||||
|
await setTypeDialogUser('Edit') |
||||||
|
setOpenDialogUser(true) |
||||||
|
} |
||||||
|
const handleDeleteUser = async (id) => { |
||||||
|
await setAlertDelete(true) |
||||||
|
await setIdDelete(id) |
||||||
|
} |
||||||
|
|
||||||
|
const closeDialogUser = (type, message) => { |
||||||
|
setOpenDialogUser(false); |
||||||
|
if (type == 'success') { |
||||||
|
NotificationManager.success(`${message}`, "Success!!"); |
||||||
|
getDataUser() |
||||||
|
} else if (type == 'Failed') { |
||||||
|
NotificationManager.error(`${message}`, "Failed!!"); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const handleAddMenu = async () => { |
||||||
|
await setTypeDialogMenu("Save") |
||||||
|
setOpenDialogMenu(true) |
||||||
|
} |
||||||
|
|
||||||
|
const handleEditMenu = async (data) => { |
||||||
|
setDataEdit(data) |
||||||
|
await setTypeDialogMenu('Edit') |
||||||
|
setOpenDialogMenu(true) |
||||||
|
} |
||||||
|
|
||||||
|
const handleDeleteMenu = async (id) => { |
||||||
|
await setAlertDelete(true) |
||||||
|
await setIdDelete(id) |
||||||
|
} |
||||||
|
|
||||||
|
const closeDialogMenu = (type, message) => { |
||||||
|
setOpenDialogMenu(false); |
||||||
|
if (type == 'success') { |
||||||
|
NotificationManager.success(`${message}`, "Success!!"); |
||||||
|
getDataMenu() |
||||||
|
} else if (type == 'Failed') { |
||||||
|
NotificationManager.error(`${message}`, "Failed!!"); |
||||||
|
} |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
const handleSave = () => { |
||||||
|
let data = ''; |
||||||
|
|
||||||
|
if (!registrationnumber && registrationnumber === "") { |
||||||
|
alert("Please input Registration Number"); |
||||||
|
return; |
||||||
|
} |
||||||
|
if (!companyName && companyName === "") { |
||||||
|
alert("Please input the name"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (typeDialog === "Save") { |
||||||
|
data = { |
||||||
|
registration_no: registrationnumber, |
||||||
|
company_name: companyName, |
||||||
|
address: addressCompany, |
||||||
|
phone_no: phoneNumber, |
||||||
|
email: emailCompany, |
||||||
|
description: description, |
||||||
|
logo_login: logoLogin, |
||||||
|
logo_header: logoHeader, |
||||||
|
favicon_image: favIcon, |
||||||
|
login_instruction: loginInstruction, |
||||||
|
about: about, |
||||||
|
html_title: htmlTitle, |
||||||
|
app_name: appName, |
||||||
|
base_url: baseUrl, |
||||||
|
is_active: statusCompany, |
||||||
|
template_id: template |
||||||
|
} |
||||||
|
console.log(data) |
||||||
|
|
||||||
|
closeDialog('save', data); |
||||||
|
} else if (typeDialog === "Set") { |
||||||
|
// if (!password && password === "") {
|
||||||
|
// alert("Please fill password");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (password !== retryPassword) {
|
||||||
|
// alert("Password doesn't match");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (password.length < 8) {
|
||||||
|
// alert("Password minimum 8 character");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// data = {
|
||||||
|
// id,
|
||||||
|
// username,
|
||||||
|
// password,
|
||||||
|
// email,
|
||||||
|
// }
|
||||||
|
|
||||||
|
closeDialog('edit', data); |
||||||
|
} else { |
||||||
|
|
||||||
|
// data = {
|
||||||
|
// id,
|
||||||
|
// name: resourceName,
|
||||||
|
// username,
|
||||||
|
// employee_type: employeeType,
|
||||||
|
// phone_number: phoneNo,
|
||||||
|
// email,
|
||||||
|
// gender,
|
||||||
|
// birth_place: birthPlace,
|
||||||
|
// blood_type: bloodType,
|
||||||
|
// ktp_number: ktpNumber,
|
||||||
|
// biaya_per_jam: biayaPerJam.replace('.', ''),
|
||||||
|
// role_id: roleId,
|
||||||
|
// divisi_id: divisionId,
|
||||||
|
// address,
|
||||||
|
// status_resource: statusResource,
|
||||||
|
// status_boundary: statusRestriction,
|
||||||
|
// company_id: company_id
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (birthDate && birthDate != "") {
|
||||||
|
// data['birth_date'] = birthDate;
|
||||||
|
// }
|
||||||
|
|
||||||
|
closeDialog('edit', data); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const isValidEmail = (email) => { |
||||||
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; |
||||||
|
return emailRegex.test(email); |
||||||
|
}; |
||||||
|
|
||||||
|
const handleCancel = () => { |
||||||
|
closeDialog('cancel', 'none') |
||||||
|
setDatatable([]) |
||||||
|
} |
||||||
|
|
||||||
|
const onConfirmDelete = async () => { |
||||||
|
let url = USER_DELETE(idDelete); |
||||||
|
|
||||||
|
const result = await axios.delete(url, config) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
getDataUser() |
||||||
|
setIdDelete(0) |
||||||
|
setAlertDelete(false) |
||||||
|
NotificationManager.success(`Data user berhasil dihapus!`, 'Success!!'); |
||||||
|
} else { |
||||||
|
setIdDelete(0) |
||||||
|
setAlertDelete(false) |
||||||
|
NotificationManager.error(`Data user gagal dihapus!`, 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const cancelDelete = () => { |
||||||
|
setAlertDelete(false) |
||||||
|
setIdDelete(0) |
||||||
|
} |
||||||
|
|
||||||
|
const addBaseUrl = () => { |
||||||
|
baseUrl.push({ |
||||||
|
id: lastIdxURL + 1, |
||||||
|
url: "", |
||||||
|
}); |
||||||
|
setBaseUrl(baseUrl); |
||||||
|
setLastIdxURL(lastIdxURL + 1); |
||||||
|
}; |
||||||
|
|
||||||
|
const handleChangeBaseURL = (value, index) => { |
||||||
|
const newBaseURL = [...baseUrl]; |
||||||
|
newBaseURL[index] = value; |
||||||
|
setBaseUrl(newBaseURL); |
||||||
|
} |
||||||
|
|
||||||
|
const deleteBaseURL = (id) => { |
||||||
|
if (baseUrl && baseUrl.length > 0) { |
||||||
|
let checkIdx = baseUrl.findIndex((o) => o.id === id); |
||||||
|
if (checkIdx > -1) { |
||||||
|
baseUrl.splice(checkIdx, 1); |
||||||
|
setBaseUrl(baseUrl.filter((_, i2) => i2 !== id)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const handleLogoHeader = (content) => { |
||||||
|
const newLogoHeader = [...logoHeader, { |
||||||
|
type: "image", |
||||||
|
content: content, |
||||||
|
}]; |
||||||
|
setLogoHeader(newLogoHeader); |
||||||
|
} |
||||||
|
|
||||||
|
const RenderBaseURL = () => { |
||||||
|
if (baseUrl.length > 0) { |
||||||
|
return baseUrl.map((item, index) => { |
||||||
|
return ( |
||||||
|
<Row key={index} style={{ marginBottom: 10 }}> |
||||||
|
<Col md={8}> |
||||||
|
<Input |
||||||
|
type="text" |
||||||
|
value={item.url} |
||||||
|
name="item" |
||||||
|
onChange={(e) => handleChangeBaseURL(e, index)} |
||||||
|
/> |
||||||
|
</Col> |
||||||
|
<Col md={2}> |
||||||
|
<Button |
||||||
|
color="danger" |
||||||
|
size="sm" |
||||||
|
onClick={() => deleteBaseURL(item.id)} |
||||||
|
> |
||||||
|
<i className="fa fa-trash"></i> |
||||||
|
</Button> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
); |
||||||
|
}); |
||||||
|
} else if (baseUrl.length < 1) { |
||||||
|
return ( |
||||||
|
<div |
||||||
|
style={{ |
||||||
|
textAlign: "center", |
||||||
|
color: "red", |
||||||
|
marginTop: 25, |
||||||
|
marginBottom: 25, |
||||||
|
}} |
||||||
|
> |
||||||
|
No Base URL found |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
const renderFromCompany = () => { |
||||||
|
return ( |
||||||
|
<Form> |
||||||
|
<Row> |
||||||
|
<Col md={12}> |
||||||
|
<span style={{ color: "red" }}>*</span>required. |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Number Registration<span style={{ color: "red" }}>*</span></Label> |
||||||
|
<Input type="text" value={registrationnumber} onChange={(e) => setRegistrationNumber(e.target.value)} placeholder='Input Number Registration' /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Company Name<span style={{ color: "red" }}>*</span></Label> |
||||||
|
<Input type="text" value={companyName} onChange={(e) => setCompanyName(e.target.value)} placeholder=' Input Company Name' /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Email</Label> |
||||||
|
<Input type="email" value={emailCompany} onChange={(e) => setEmailCompany(e.target.value)} placeholder={t('inputEmail')} |
||||||
|
onBlur={(e) => { |
||||||
|
if (!isValidEmail(e.target.value)) { |
||||||
|
alert("Masukkan email yang valid."); |
||||||
|
} |
||||||
|
}} |
||||||
|
/> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Phone Number</Label> |
||||||
|
<Input type="text" value={phoneNumber} onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))} placeholder={t('inputNoPhone')} maxLength="15" /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Address</Label> |
||||||
|
<Input type="textarea" value={addressCompany} onChange={(e) => setAddressCompany(e.target.value)} placeholder=' Input Address' /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">About</Label> |
||||||
|
<Input type="textarea" value={about} onChange={(e) => setAbout(e.target.value)} placeholder=' Input Company Name' /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">App Name</Label> |
||||||
|
<Input type="text" value={appName} onChange={(e) => setAppName(e.target.value)} placeholder=' Input App Name' /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">HTML Title</Label> |
||||||
|
<Input type="text" value={htmlTitle} onChange={(e) => setHtmlTitle(e.target.value)} placeholder=' Input HTML Title' /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Status Company<span style={{ color: "red" }}>*</span></Label> |
||||||
|
<Select style={{ width: "100%" }} defaultValue={statusCompany} onChange={(e) => setStatusCompany(e)} placeholder="Select a template for application"> |
||||||
|
<Option value={true}>Active</Option> |
||||||
|
<Option value={false}>Inactive</Option> |
||||||
|
</Select> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Template Application<span style={{ color: "red" }}>*</span></Label> |
||||||
|
<Select style={{ width: "100%" }} defaultValue={template} onChange={(e) => setTemplate(e)} placeholder="Select a template for application"> |
||||||
|
<Option value={'1'}>Construction</Option> |
||||||
|
<Option value={'2'}>IT (Information AND Technology)</Option> |
||||||
|
</Select> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<Col md={12}> |
||||||
|
<Label className="capitalize">Base URL<span style={{ color: "red" }}>*</span></Label> |
||||||
|
<Row> |
||||||
|
<Col md={8}> |
||||||
|
<p>URL</p> |
||||||
|
</Col> |
||||||
|
<Col md={2}> |
||||||
|
<p>Action</p> |
||||||
|
</Col> |
||||||
|
<Col md={1}> |
||||||
|
<Tooltip title="Add row"> |
||||||
|
<Button |
||||||
|
size="sm" |
||||||
|
color="primary" |
||||||
|
onClick={() => addBaseUrl()} |
||||||
|
> |
||||||
|
<i className="fa fa-plus"></i> |
||||||
|
</Button> |
||||||
|
</Tooltip> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<div style={{ marginBottom: 50 }}>{RenderBaseURL()}</div> |
||||||
|
</Col> |
||||||
|
</Col> |
||||||
|
<Col md={6}> |
||||||
|
<Row> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize" style={{ fontWeight: "bold" }}>Logo Login</Label> |
||||||
|
<Input |
||||||
|
type="file" |
||||||
|
accept="image/*" |
||||||
|
// onChange={(e) => handleLogoHeader(e.target.files[0])}
|
||||||
|
/> |
||||||
|
</FormGroup> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize" style={{ fontWeight: "bold" }}>Logo Header</Label> |
||||||
|
<Input |
||||||
|
type="file" |
||||||
|
accept="image/*" |
||||||
|
onChange={(e) => handleLogoHeader(e.target.files[0])} |
||||||
|
/> |
||||||
|
</FormGroup> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize" style={{ fontWeight: "bold" }}>Fav Icon Logo</Label> |
||||||
|
<Input |
||||||
|
type="file" |
||||||
|
accept="image/*" |
||||||
|
// onChange={(e) => setProjectStructureOrg(e.target.files[0])}
|
||||||
|
/> |
||||||
|
</FormGroup> |
||||||
|
</Row> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</Form> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const RenderTableUser = useMemo(() => { |
||||||
|
const columns = [ |
||||||
|
{ |
||||||
|
title: t('action'), |
||||||
|
dataIndex: '', |
||||||
|
key: 'x', |
||||||
|
render: (text, record) => <> |
||||||
|
<Tooltip title={t('edit')}> |
||||||
|
<Button size={"sm"} color='success' onClick={() => handleEditUser(text)}><i className="fa fa-edit"></i></Button> |
||||||
|
</Tooltip>{" "} |
||||||
|
<Tooltip title={t('delete')}> |
||||||
|
<Button size={"sm"} color='danger' onClick={() => handleDeleteUser(text.id)}><i className="fa fa-trash"></i></Button> |
||||||
|
</Tooltip> |
||||||
|
</>, |
||||||
|
}, |
||||||
|
|
||||||
|
{ title: t('nik'), dataIndex: 'ktp_number', key: 'ktp_number' }, |
||||||
|
{ title: t('nameHR'), dataIndex: 'name', key: 'name' }, |
||||||
|
|
||||||
|
{ title: t('employeeType'), dataIndex: 'employee_type', key: 'employee_type' }, |
||||||
|
{ |
||||||
|
title: t('roles'), |
||||||
|
dataIndex: 'join_first_name', |
||||||
|
key: 'join_first_name', |
||||||
|
render: (text, record) => <>{record.join_first_name}</> |
||||||
|
}, |
||||||
|
{ title: 'Phone No.', dataIndex: 'phone_number', key: 'phone_number' }, |
||||||
|
{ title: 'Email', dataIndex: 'email', key: 'email' }, |
||||||
|
{ title: 'Status', dataIndex: 'status_resource', key: 'status_status' } |
||||||
|
]; |
||||||
|
return ( |
||||||
|
<Table |
||||||
|
rowKey="id" |
||||||
|
size="small" |
||||||
|
columns={columns} |
||||||
|
dataSource={dataTable} |
||||||
|
pagination={false} |
||||||
|
/> |
||||||
|
) |
||||||
|
}, [dataTable]) |
||||||
|
|
||||||
|
|
||||||
|
const renderTableMenu = useMemo(() => { |
||||||
|
const columns = [ |
||||||
|
{ |
||||||
|
title: t('action'), |
||||||
|
dataIndex: '', |
||||||
|
key: 'x', |
||||||
|
render: (text, record) => <> |
||||||
|
<Tooltip title={t('delete')}> |
||||||
|
<i id="TooltipDelete" className="fa fa-trash" style={{ color: 'red', marginRight: '10px', cursor: "pointer" }} onClick={() => handleDeleteMenu(text.id)}></i> |
||||||
|
</Tooltip> |
||||||
|
<Tooltip title={t('edit')}> |
||||||
|
<i id="TooltipEdit" className="fa fa-edit" style={{ color: 'green', cursor: "pointer" }} onClick={() => handleEditMenu(text)}></i> |
||||||
|
</Tooltip> |
||||||
|
</>, |
||||||
|
}, |
||||||
|
{ title: t('name'), dataIndex: 'join_first_name', key: 'join_first_name' }, |
||||||
|
{ title: 'Url', dataIndex: 'url', key: 'url' }, |
||||||
|
{ title: t('icon'), dataIndex: 'icon', key: 'icon' }, |
||||||
|
{ title: 'Alias', dataIndex: 'alias_name', key: 'alias_name' }, |
||||||
|
{ title: t('order'), dataIndex: 'sequence', key: 'sequence' }, |
||||||
|
{ title: t('parentMenu'), dataIndex: 'join_first_name', key: 'join_first_name', render: (text, record) => (text ? text : "-") } |
||||||
|
]; |
||||||
|
return ( |
||||||
|
<Table |
||||||
|
rowKey="id" |
||||||
|
size="small" |
||||||
|
columns={columns} |
||||||
|
dataSource={dataTableMenu} |
||||||
|
pagination={false} |
||||||
|
/> |
||||||
|
) |
||||||
|
}, [dataTableMenu]) |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<NotificationContainer /> |
||||||
|
<SweetAlert |
||||||
|
show={alertDelete} |
||||||
|
warning |
||||||
|
showCancel |
||||||
|
confirmBtnText="Delete" |
||||||
|
confirmBtnBsStyle="danger" |
||||||
|
title={t('deleteConfirm')} |
||||||
|
onConfirm={onConfirmDelete} |
||||||
|
onCancel={() => cancelDelete()} |
||||||
|
focusCancelBtn |
||||||
|
> |
||||||
|
{t('deleteMsg')} |
||||||
|
</SweetAlert> |
||||||
|
<DialogFormUser |
||||||
|
openDialog={openDialogUser} |
||||||
|
closeDialog={closeDialogUser} |
||||||
|
typeDialog={typeDialogUser} |
||||||
|
roleList={roleList} |
||||||
|
companyID={companyID} |
||||||
|
dataEdit={dataEdit} |
||||||
|
/> |
||||||
|
<DialogFormMenu |
||||||
|
openDialog={openDialogMenu} |
||||||
|
closeDialog={closeDialogMenu} |
||||||
|
typeDialog={typeDialogMenu} |
||||||
|
companyID={companyID} |
||||||
|
companyName={companyNameProp} |
||||||
|
dataEdit={dataEdit} |
||||||
|
/> |
||||||
|
<Modal size="xl" fullscreen="xl" scrollable={true} isOpen={openDialog} toggle={toggleDialog}> |
||||||
|
<ModalHeader className="capitalize withBtn" toggle={closeDialog} style={{ width: "100%" }}> |
||||||
|
{typeDialog === "Set-Menu" ? `Menu ${companyNameProp}` : typeDialog === "Save" ? `Add Data Company` : typeDialog === "Set" ? `Manage User ${companyNameProp}` : `Edit ${companyNameProp}`} |
||||||
|
{typeDialog === "Set" ? ( |
||||||
|
<Tooltip title="Add User"> |
||||||
|
<Button onClick={handleAddUser} size='sm' color="primary"><i className='fa fa-plus'></i></Button> |
||||||
|
</Tooltip> |
||||||
|
) : |
||||||
|
( |
||||||
|
<Tooltip title="Add Menu"> |
||||||
|
<Button onClick={handleAddMenu} size='sm' color="primary"><i className='fa fa-plus'></i></Button> |
||||||
|
</Tooltip> |
||||||
|
)} |
||||||
|
</ModalHeader> |
||||||
|
<ModalBody> |
||||||
|
|
||||||
|
{typeDialog !== "Set" && typeDialog !== "Set-Menu" && renderFromCompany()} |
||||||
|
{typeDialog === "Set" && ( |
||||||
|
<> |
||||||
|
{RenderTableUser} |
||||||
|
<Pagination |
||||||
|
style={{ marginTop: "25px" }} |
||||||
|
showSizeChanger |
||||||
|
onShowSizeChange={onShowSizeChange} |
||||||
|
onChange={onPagination} |
||||||
|
pageSizeOptions={["10", "25", "50"]} |
||||||
|
total={totalPage} |
||||||
|
pageSize={rowsPerPage} |
||||||
|
current={currentPage} |
||||||
|
/> |
||||||
|
</> |
||||||
|
)} |
||||||
|
{typeDialog === "Set-Menu" && ( |
||||||
|
<> |
||||||
|
{renderTableMenu} |
||||||
|
<Pagination |
||||||
|
style={{ marginTop: "25px" }} |
||||||
|
showSizeChanger |
||||||
|
onShowSizeChange={onShowSizeChangeMenu} |
||||||
|
onChange={onPaginationMenu} |
||||||
|
pageSizeOptions={["10", "25", "50"]} |
||||||
|
total={totalPageMenu} |
||||||
|
pageSize={rowsPerPageMenu} |
||||||
|
current={currentPageMenu} |
||||||
|
/> |
||||||
|
</> |
||||||
|
)} |
||||||
|
|
||||||
|
</ModalBody> |
||||||
|
<ModalFooter> |
||||||
|
{typeDialog !== "Set" && typeDialog !== "Set-Menu" && ( |
||||||
|
<Button color="primary" onClick={() => handleSave()}>{typeDialog}</Button> |
||||||
|
)} |
||||||
|
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>cancel</Button> |
||||||
|
</ModalFooter> |
||||||
|
</Modal> |
||||||
|
</> |
||||||
|
) |
||||||
|
|
||||||
|
} |
||||||
|
export default DialogForm; |
@ -0,0 +1,285 @@ |
|||||||
|
import React, { useState, useEffect } from 'react' |
||||||
|
import { |
||||||
|
Modal, ModalHeader, ModalBody, ModalFooter, |
||||||
|
Button, Form, FormGroup, Label, Input, Col, Row |
||||||
|
} from 'reactstrap'; |
||||||
|
import { Transfer, Select } from 'antd'; |
||||||
|
import 'antd/dist/antd.css'; |
||||||
|
import { useTranslation } from 'react-i18next'; |
||||||
|
import { MENU_LIST, MENU_COMPANY_ADD, MENU_COMPANY_EDIT } from '../../../const/ApiConst.js'; |
||||||
|
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||||
|
import axios from 'axios'; |
||||||
|
const token = window.localStorage.getItem('token'); |
||||||
|
const FormMenu = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdit, companyName, companyID }) => { |
||||||
|
const { Option } = Select |
||||||
|
const [targetKeys, setTargetKeys] = useState([]) |
||||||
|
const [menuResource, setmenuResource] = useState([]) |
||||||
|
const [id, setId] = useState(0) |
||||||
|
const [name, setName] = useState('') |
||||||
|
const [url, setUrl] = useState('') |
||||||
|
const [aliasName, setAliasName] = useState('') |
||||||
|
const [icon, setIcon] = useState('') |
||||||
|
const [sequence, setSequence] = useState(0) |
||||||
|
const [parentId, setParentId] = useState(null) |
||||||
|
const { t } = useTranslation() |
||||||
|
const config = { |
||||||
|
headers: |
||||||
|
{ |
||||||
|
Authorization: `Bearer ${token}`, |
||||||
|
"Content-type": `application/json` |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const handleCLearData = () => { |
||||||
|
// setId(0)
|
||||||
|
setTargetKeys([]) |
||||||
|
} |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (!openDialog) { |
||||||
|
handleCLearData() |
||||||
|
} else { |
||||||
|
getDataAllMenu(); |
||||||
|
} |
||||||
|
}, [openDialog]) |
||||||
|
|
||||||
|
const getDataAllMenu = async () => { |
||||||
|
const result = await axios |
||||||
|
.get(MENU_LIST, config) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code == 200) { |
||||||
|
setTransferMenu(result.data.data); |
||||||
|
} else { |
||||||
|
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const setTransferMenu = (data) => { |
||||||
|
const finalData = [] |
||||||
|
data.map((val, index) => { |
||||||
|
let data = { |
||||||
|
key: val.id, |
||||||
|
name: val.name, |
||||||
|
url: val.url, |
||||||
|
alias_name: val.alias_name, |
||||||
|
icon: val.icon, |
||||||
|
parent_id: val.parent_id, |
||||||
|
sequence: val.sequence, |
||||||
|
} |
||||||
|
finalData.push(data) |
||||||
|
}); |
||||||
|
setmenuResource(finalData) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const handleSave = async () => { |
||||||
|
await saveMenuCompany() |
||||||
|
handleCLearData() |
||||||
|
} |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (typeDialog === "Edit") { |
||||||
|
setId(dataEdit.id) |
||||||
|
setIcon(dataEdit.icon) |
||||||
|
setParentId(dataEdit.parent_id) |
||||||
|
setSequence(dataEdit.sequence) |
||||||
|
} else { |
||||||
|
setId(0) |
||||||
|
setName('') |
||||||
|
setUrl('') |
||||||
|
setIcon('') |
||||||
|
setParentId(null) |
||||||
|
setSequence(0) |
||||||
|
setAliasName('') |
||||||
|
} |
||||||
|
}, [dataEdit, openDialog]) |
||||||
|
|
||||||
|
const validation = () => { |
||||||
|
if (!icon || icon === "") { |
||||||
|
alert("Icon cannot be empty!"); |
||||||
|
return true; |
||||||
|
} |
||||||
|
if (sequence < 0) { |
||||||
|
alert("Order cannot be empty!"); |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const saveMenuCompany = async () => { |
||||||
|
let data = ''; |
||||||
|
const err = validation(); |
||||||
|
if (!err) { |
||||||
|
if (typeDialog === "Edit") { |
||||||
|
data = { |
||||||
|
id, |
||||||
|
sequence: parseInt(sequence), |
||||||
|
icon, |
||||||
|
} |
||||||
|
|
||||||
|
if (parentId && parentId > 0) { |
||||||
|
data['parent_id'] = parentId |
||||||
|
} |
||||||
|
|
||||||
|
const formData = data |
||||||
|
const url = MENU_COMPANY_EDIT(data.id) |
||||||
|
const result = await axios.put(url, formData, config) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
closeDialog('success', 'Data menu berhasil diubah') |
||||||
|
} else { |
||||||
|
closeDialog('failed', 'Data menu gagal diubah') |
||||||
|
} |
||||||
|
} |
||||||
|
setId(0) |
||||||
|
setName('') |
||||||
|
setUrl('') |
||||||
|
setIcon('') |
||||||
|
setParentId(null) |
||||||
|
setSequence(0) |
||||||
|
setAliasName('') |
||||||
|
} else { |
||||||
|
const selectedData = menuResource.filter(item => targetKeys.includes(item.key)); |
||||||
|
const formDatas = selectedData.map(data => ({ |
||||||
|
menu_id: data.key, |
||||||
|
parent_id: data.parent_id, |
||||||
|
company_id: companyID, |
||||||
|
icon: data.icon, |
||||||
|
alias_name: data.alias_name, |
||||||
|
url: data.url, |
||||||
|
sequence: data.sequence |
||||||
|
})); |
||||||
|
const result = await axios |
||||||
|
.post(MENU_COMPANY_ADD, formDatas, config) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
if (result && result.status == 200) { |
||||||
|
closeDialog('success', result.data.message) |
||||||
|
} else { |
||||||
|
closeDialog('failed', result.data.message) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const handleCancel = () => { |
||||||
|
closeDialog('cancel', 'none') |
||||||
|
setId(0) |
||||||
|
setName('') |
||||||
|
setUrl('') |
||||||
|
setIcon('') |
||||||
|
setParentId(null) |
||||||
|
setSequence(0) |
||||||
|
setAliasName('') |
||||||
|
} |
||||||
|
|
||||||
|
const handleChange = targetKeys => { |
||||||
|
setTargetKeys(targetKeys) |
||||||
|
}; |
||||||
|
|
||||||
|
const onChangeParent = (val) => { |
||||||
|
setParentId(val) |
||||||
|
} |
||||||
|
|
||||||
|
const setupSelectParent = () => { |
||||||
|
return ( |
||||||
|
<> |
||||||
|
{menuResource.map((val, index) => { |
||||||
|
return ( |
||||||
|
<Option key={index} value={val.id}>{val.name}</Option> |
||||||
|
) |
||||||
|
})} |
||||||
|
</> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
const renderForm = () => { |
||||||
|
return ( |
||||||
|
<Form> |
||||||
|
<Row> |
||||||
|
<Col md={12}> |
||||||
|
<div style={{ justifyContent: 'center' }}> |
||||||
|
<Transfer |
||||||
|
showSearch |
||||||
|
listStyle={{ |
||||||
|
width: 250, |
||||||
|
height: 300, |
||||||
|
}} |
||||||
|
titles={['Master Menu', `Menu ${companyName}`]} |
||||||
|
targetKeys={targetKeys} |
||||||
|
dataSource={menuResource} |
||||||
|
onChange={handleChange} |
||||||
|
render={item => item.name} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
|
||||||
|
</Form> |
||||||
|
) |
||||||
|
} |
||||||
|
const renderFormEdit = () => { |
||||||
|
return ( |
||||||
|
<Form> |
||||||
|
<Row> |
||||||
|
<Col md={12}> |
||||||
|
<span style={{ color: "red" }}>*</span> Wajib diisi. |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col> |
||||||
|
{/* <FormGroup> |
||||||
|
<Label className="capitalize">{t('name')} Menu<span style={{ color: "red" }}>*</span></Label> |
||||||
|
<Input type="hidden" value={name} onChange={(e) => setName(e.target.value)} placeholder={t('inputName')} /> |
||||||
|
</FormGroup> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">URL<span style={{ color: "red" }}>*</span></Label> |
||||||
|
<Input type="hidden" value={url} onChange={(e) => setUrl(e.target.value)} placeholder={t('inputUrl')} /> |
||||||
|
</FormGroup> */} |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">{t('icon')}<span style={{ color: "red" }}>*</span> </Label> |
||||||
|
<Input type="text" value={icon} onChange={(e) => setIcon(e.target.value)} placeholder={t('inputIcon')} /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">{t('order')}<span style={{ color: "red" }}>*</span></Label> |
||||||
|
<Input type="text" min="0" value={sequence} onChange={(e) => setSequence(e.target.value.replace(/[^0-9]/g, ''))} placeholder={t('inputOrder')} /> |
||||||
|
</FormGroup> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">{t('parentMenu')}</Label> |
||||||
|
<Select showSearch defaultValue={parentId} onChange={onChangeParent} placeholder={t('inputParentMenu')} style={{ width: '100%' }}> |
||||||
|
{setupSelectParent()} |
||||||
|
</Select> |
||||||
|
</FormGroup> |
||||||
|
{/* <FormGroup> |
||||||
|
<Label className="capitalize">Alias Menu</Label> |
||||||
|
<Input type="hidden" value={aliasName} onChange={(e) => setAliasName(e.target.value)} placeholder={t('inputAliasMenu')} /> |
||||||
|
</FormGroup> */} |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
|
||||||
|
</Form> |
||||||
|
) |
||||||
|
} |
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Modal ssize="md" scrollable={true} isOpen={openDialog} toggle={toggleDialog}> |
||||||
|
<ModalHeader className="capitalize withBtn" toggle={closeDialog} style={{ width: "100%" }}> |
||||||
|
Add Data Menu |
||||||
|
</ModalHeader> |
||||||
|
<ModalBody> |
||||||
|
{typeDialog !== 'Edit' ? renderForm() : renderFormEdit()} |
||||||
|
</ModalBody> |
||||||
|
<ModalFooter> |
||||||
|
<Button color="primary" onClick={() => handleSave()}>{typeDialog}</Button>{''} |
||||||
|
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>cancel</Button> |
||||||
|
</ModalFooter> |
||||||
|
</Modal> |
||||||
|
</> |
||||||
|
) |
||||||
|
|
||||||
|
} |
||||||
|
export default FormMenu; |
@ -0,0 +1,267 @@ |
|||||||
|
import React, { useState, useEffect } from 'react' |
||||||
|
import { |
||||||
|
Modal, ModalHeader, ModalBody, ModalFooter, |
||||||
|
Button, Form, FormGroup, Label, Input, Col, Row |
||||||
|
} from 'reactstrap'; |
||||||
|
import { Select } from 'antd'; |
||||||
|
import { USER_ADD, USER_EDIT } from '../../../const/ApiConst.js'; |
||||||
|
import 'antd/dist/antd.css'; |
||||||
|
import { useTranslation } from 'react-i18next'; |
||||||
|
import axios from 'axios'; |
||||||
|
const { Option } = Select |
||||||
|
const token = window.localStorage.getItem('token'); |
||||||
|
const config = { |
||||||
|
headers: |
||||||
|
{ |
||||||
|
Authorization: `Bearer ${token}`, |
||||||
|
"Content-type": `application/json` |
||||||
|
} |
||||||
|
}; |
||||||
|
const FormUser = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdit, roleList, companyID }) => { |
||||||
|
const { t } = useTranslation() |
||||||
|
const [id, setId] = useState('') |
||||||
|
const [resourceName, setResourceName] = useState('') |
||||||
|
const [username, setUsername] = useState('') |
||||||
|
const [password, setPassword] = useState('') |
||||||
|
const [employeeType, setEmployeeType] = useState('') |
||||||
|
const [phoneNo, setPhoneNo] = useState('') |
||||||
|
const [email, setEmail] = useState('') |
||||||
|
const [gender, setGender] = useState('') |
||||||
|
const [ktpNumber, setKtpNumber] = useState('') |
||||||
|
const [roleId, setRoleId] = useState('') |
||||||
|
const [statusResource, setStatusResource] = useState('active') |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (typeDialog === "Edit") { |
||||||
|
console.log(dataEdit); |
||||||
|
setId(dataEdit.id) |
||||||
|
setResourceName(dataEdit.name) |
||||||
|
setUsername(dataEdit.username) |
||||||
|
setPassword('') |
||||||
|
setEmployeeType(dataEdit.employee_type) |
||||||
|
setPhoneNo(dataEdit.phone_number) |
||||||
|
setEmail(dataEdit.email) |
||||||
|
setGender(dataEdit.gender) |
||||||
|
setKtpNumber(dataEdit.ktp_number ? dataEdit.ktp_number : '') |
||||||
|
setRoleId(dataEdit.role_id) |
||||||
|
} else { |
||||||
|
setId(0) |
||||||
|
setResourceName('') |
||||||
|
setUsername('') |
||||||
|
setPassword('') |
||||||
|
setEmployeeType('') |
||||||
|
setPhoneNo('') |
||||||
|
setEmail('') |
||||||
|
setGender('') |
||||||
|
setRoleId('') |
||||||
|
} |
||||||
|
}, [dataEdit, openDialog]) |
||||||
|
|
||||||
|
|
||||||
|
const handleSave = async () => { |
||||||
|
let data = ''; |
||||||
|
if (typeDialog === "Save") { |
||||||
|
data = { |
||||||
|
name: resourceName, |
||||||
|
employee_type: employeeType, |
||||||
|
phone_number: phoneNo, |
||||||
|
email, |
||||||
|
gender, |
||||||
|
ktp_number: ktpNumber, |
||||||
|
role_id: roleId, |
||||||
|
status_resource: statusResource, |
||||||
|
company_id: companyID, |
||||||
|
username, |
||||||
|
password, |
||||||
|
} |
||||||
|
const formData = data |
||||||
|
const result = await axios.post(USER_ADD, formData, config) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
closeDialog('success', `Data resource berhasil ditambah`) |
||||||
|
} else { |
||||||
|
closeDialog('failed', result.data.message) |
||||||
|
} |
||||||
|
} else { |
||||||
|
|
||||||
|
data = { |
||||||
|
id, |
||||||
|
name: resourceName, |
||||||
|
username, |
||||||
|
employee_type: employeeType, |
||||||
|
phone_number: phoneNo, |
||||||
|
email, |
||||||
|
gender, |
||||||
|
ktp_number: ktpNumber, |
||||||
|
role_id: roleId, |
||||||
|
status_resource: statusResource, |
||||||
|
company_id: companyID, |
||||||
|
username, |
||||||
|
password, |
||||||
|
} |
||||||
|
if (password == '') { |
||||||
|
data.password = dataEdit.password; |
||||||
|
} |
||||||
|
let urlEdit = USER_EDIT(data.id) |
||||||
|
const formData = data |
||||||
|
|
||||||
|
const result = await axios.put(urlEdit, formData, config) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
closeDialog('success', `Data resource berhasil diedit`) |
||||||
|
} else { |
||||||
|
closeDialog('failed', result.data.message) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const handleCancel = () => { |
||||||
|
closeDialog('cancel', 'none') |
||||||
|
} |
||||||
|
|
||||||
|
const isValidEmail = (email) => { |
||||||
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; |
||||||
|
return emailRegex.test(email); |
||||||
|
}; |
||||||
|
|
||||||
|
const setupSelectRole = () => { |
||||||
|
return ( |
||||||
|
<> |
||||||
|
{roleList.map((val, index) => { |
||||||
|
return ( |
||||||
|
<Option key={index} value={val.id}>{val.name}</Option> |
||||||
|
) |
||||||
|
})} |
||||||
|
</> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const renderFormSetAdmin = () => { |
||||||
|
return ( |
||||||
|
<Form> |
||||||
|
<Row> |
||||||
|
<Col md={12}> |
||||||
|
<span style={{ color: "red" }}>*</span>required. |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">{t('nik')} <span style={{ color: "red" }}>*</span></Label> |
||||||
|
<Input type="text" value={ktpNumber} onChange={(e) => setKtpNumber(e.target.value.replace(/[^0-9]/g, ''))} placeholder={t('inputNik')} maxLength="16" /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">{t('nameHR')}<span style={{ color: "red" }}>*</span></Label> |
||||||
|
<Input type="text" value={resourceName} onChange={(e) => setResourceName(e.target.value)} placeholder={t('inputName')} /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">{t('employeeType')} <span style={{ color: "red" }}>*</span></Label> |
||||||
|
<Select showSearch value={employeeType} defaultValue={employeeType} onChange={(val) => setEmployeeType(val)} placeholder="Select Employee Type" style={{ width: '100%' }}> |
||||||
|
<Option value={'employee'}>Employee</Option> |
||||||
|
<Option value={'subcon'}>Subcon</Option> |
||||||
|
<Option value={'freelance'}>Freelance</Option> |
||||||
|
</Select> |
||||||
|
</FormGroup> |
||||||
|
|
||||||
|
</Col> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Phone No.</Label> |
||||||
|
<Input type="text" value={phoneNo} onChange={(e) => setPhoneNo(e.target.value.replace(/[^0-9]/g, ''))} placeholder={t('inputNoPhone')} maxLength="15" /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Email</Label> |
||||||
|
<Input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder={t('inputEmail')} |
||||||
|
onBlur={(e) => { |
||||||
|
if (!isValidEmail(e.target.value)) { |
||||||
|
alert("Masukkan email yang valid."); |
||||||
|
} |
||||||
|
}} |
||||||
|
/> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">{t('gender')}</Label> |
||||||
|
<Select showSearch value={gender} defaultValue={gender} onChange={(val) => setGender(val)} placeholder={t('selectGender')} style={{ width: '100%' }}> |
||||||
|
<Option value="Male">Male</Option> |
||||||
|
<Option value="Female">Female</Option> |
||||||
|
{/* <Option value="Other">Other</Option> */} |
||||||
|
</Select> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">{t('roles')} <span style={{ color: "red" }}>*</span></Label> |
||||||
|
<Select showSearch defaultValue={roleId} onChange={(val) => setRoleId(val)} placeholder={t('selectRole')} style={{ width: '100%' }}> |
||||||
|
{setupSelectRole()} |
||||||
|
</Select> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Status</Label> |
||||||
|
<Select style={{ width: "100%" }} defaultValue={statusResource} onChange={(e) => setStatusResource(e)} > |
||||||
|
<Option value={'active'}>Active</Option> |
||||||
|
<Option value={'inactive'}>Inactive</Option> |
||||||
|
</Select> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Username</Label> |
||||||
|
<Input type="text" value={username} onChange={(e) => setUsername(e.target.value)} placeholder={`Username...`} /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Password</Label> |
||||||
|
<Input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder={`Password...`} /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</Form> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Modal size="xl" fullscreen="xl" scrollable={true} isOpen={openDialog} toggle={toggleDialog}> |
||||||
|
<ModalHeader className="capitalize withBtn" toggle={closeDialog} style={{ width: "100%" }}> |
||||||
|
{typeDialog === "Save" ? `Add` : typeDialog === "Set" ? "Add " : "Edit"} User |
||||||
|
</ModalHeader> |
||||||
|
<ModalBody> |
||||||
|
{renderFormSetAdmin()} |
||||||
|
</ModalBody> |
||||||
|
<ModalFooter> |
||||||
|
<Button color="primary" onClick={() => handleSave()}>{typeDialog}</Button>{''} |
||||||
|
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>cancel</Button> |
||||||
|
</ModalFooter> |
||||||
|
</Modal> |
||||||
|
</> |
||||||
|
) |
||||||
|
|
||||||
|
} |
||||||
|
export default FormUser; |
@ -0,0 +1,361 @@ |
|||||||
|
import * as XLSX from 'xlsx'; |
||||||
|
import React, { useState, useEffect, useMemo } from 'react'; |
||||||
|
import SweetAlert from 'react-bootstrap-sweetalert'; |
||||||
|
import axios from "../../../const/interceptorApi" |
||||||
|
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap'; |
||||||
|
import DialogForm from './DialogForm' |
||||||
|
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||||
|
import { Pagination, Table, Button, Tooltip } from 'antd'; |
||||||
|
import { |
||||||
|
COMPANY_MANAGEMENT_SEARCH, USER_ADD, USER_SEARCH, USER_EDIT, USER_DELETE, DIVISI_SEARCH, USER_SHIFT_ADD, USER_SYNC |
||||||
|
} from '../../../const/ApiConst'; |
||||||
|
import { useTranslation } from 'react-i18next'; |
||||||
|
const token = window.localStorage.getItem('token'); |
||||||
|
const config = { |
||||||
|
headers: |
||||||
|
{ |
||||||
|
Authorization: `Bearer ${token}`, |
||||||
|
"Content-type": `application/json` |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const MasterCompany = ({ params }) => { |
||||||
|
const token = localStorage.getItem("token") |
||||||
|
const company_id = localStorage.getItem("company_id") |
||||||
|
const HEADER = { |
||||||
|
headers: { |
||||||
|
"Content-Type": "application/json", |
||||||
|
"Authorization": `Bearer ${token}` |
||||||
|
} |
||||||
|
} |
||||||
|
const [alertDelete, setAlertDelete] = useState(false) |
||||||
|
const [clickOpenModal, setClickOpenModal] = useState(false) |
||||||
|
const [clickOpenModalShift, setClickOpenModalShift] = useState(false) |
||||||
|
const [currentPage, setCurrentPage] = useState(1) |
||||||
|
const [dataEdit, setDataEdit] = useState([]) |
||||||
|
const [dataExport, setDataExport] = useState([]) |
||||||
|
const [dataTable, setDatatable] = useState([]) |
||||||
|
const [divisiList, setDivisiList] = useState([]) |
||||||
|
const [idDelete, setIdDelete] = useState(0) |
||||||
|
const [openDialog, setOpenDialog] = useState(false) |
||||||
|
const [openDialogShift, setOpenDialogShift] = useState(false) |
||||||
|
const [rowsPerPage, setRowsPerPage] = useState(10) |
||||||
|
const [search, setSearch] = useState('') |
||||||
|
const [totalPage, setTotalPage] = useState(0) |
||||||
|
const [typeDialog, setTypeDialog] = useState('Save') |
||||||
|
const [typeDialogShift, setTypeDialogShift] = useState('Save') |
||||||
|
const [companyID, setCompanyID] = useState('') |
||||||
|
const [companyName, setCompanyName] = useState('') |
||||||
|
const pageName = params.name; |
||||||
|
const { t } = useTranslation(); |
||||||
|
useEffect(() => { |
||||||
|
getDivisiList() |
||||||
|
}, []) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
getDataUser() |
||||||
|
}, [search, rowsPerPage, currentPage]) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const onShowSizeChange = (current, pageSize) => { |
||||||
|
setRowsPerPage(pageSize) |
||||||
|
} |
||||||
|
|
||||||
|
const onPagination = (current, pageSize) => { |
||||||
|
setCurrentPage(current) |
||||||
|
} |
||||||
|
|
||||||
|
const getDivisiList = async () => { |
||||||
|
const formData = { |
||||||
|
"paging": { "start": 0, "length": -1 }, |
||||||
|
"orders": { "columns": ["id"], "ascending": false } |
||||||
|
} |
||||||
|
|
||||||
|
const result = await axios |
||||||
|
.post(DIVISI_SEARCH, formData, config) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code == 200) { |
||||||
|
setDivisiList(result.data.data); |
||||||
|
} else { |
||||||
|
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const getDataUser = async () => { |
||||||
|
|
||||||
|
let start = 0; |
||||||
|
|
||||||
|
if (currentPage !== 1 && currentPage > 1) { |
||||||
|
start = (currentPage * rowsPerPage) - rowsPerPage |
||||||
|
} |
||||||
|
|
||||||
|
const payload = { |
||||||
|
"paging": { |
||||||
|
"start": start, |
||||||
|
"length": rowsPerPage |
||||||
|
}, |
||||||
|
"columns": [], |
||||||
|
"group_column": { |
||||||
|
"operator": "AND", |
||||||
|
"group_operator": "OR", |
||||||
|
"where": [ |
||||||
|
{ |
||||||
|
"name": "name", |
||||||
|
"logic_operator": "~*", |
||||||
|
"value": search |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "phone_number", |
||||||
|
"logic_operator": "~*", |
||||||
|
"value": search |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "email", |
||||||
|
"logic_operator": "~*", |
||||||
|
"value": search |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "status_resource", |
||||||
|
"logic_operator": "~*", |
||||||
|
"value": search |
||||||
|
}, |
||||||
|
] |
||||||
|
}, |
||||||
|
"joins": [ |
||||||
|
|
||||||
|
], |
||||||
|
"orders": { |
||||||
|
"columns": [ |
||||||
|
"id" |
||||||
|
], |
||||||
|
"ascending": true |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const result = await axios |
||||||
|
.post(COMPANY_MANAGEMENT_SEARCH, payload, config) |
||||||
|
.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 handleSearch = e => { |
||||||
|
const value = e.target.value |
||||||
|
setSearch(value); |
||||||
|
setCurrentPage(1) |
||||||
|
}; |
||||||
|
|
||||||
|
const handleOpenDialog = async (type) => { |
||||||
|
await setTypeDialog(type) |
||||||
|
setOpenDialog(true) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleEdit = (data) => { |
||||||
|
setDataEdit(data) |
||||||
|
handleOpenDialog('Edit'); |
||||||
|
} |
||||||
|
|
||||||
|
const handleSetWorker = async (data) => { |
||||||
|
setCompanyID(data.id) |
||||||
|
setCompanyName(data.company_name) |
||||||
|
await setDataEdit(data) |
||||||
|
handleOpenDialog('Set'); |
||||||
|
} |
||||||
|
|
||||||
|
const handleSetMenu = async (data) => { |
||||||
|
setCompanyID(data.id) |
||||||
|
setCompanyName(data.company_name) |
||||||
|
await setDataEdit(data) |
||||||
|
handleOpenDialog('Set-Menu'); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const handleDelete = async (id) => { |
||||||
|
await setAlertDelete(true) |
||||||
|
await setIdDelete(id) |
||||||
|
} |
||||||
|
|
||||||
|
const handleCloseDialog = (type, data) => { |
||||||
|
if (type === "save") { |
||||||
|
saveUser(data); |
||||||
|
} else if (type === "edit") { |
||||||
|
editUser(data); |
||||||
|
} |
||||||
|
setDataEdit([]) |
||||||
|
setOpenDialog(false) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const saveUser = async (data) => { |
||||||
|
const formData = data |
||||||
|
const result = await axios.post(USER_ADD, formData, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
getDataUser(); |
||||||
|
NotificationManager.success(`Data resource berhasil ditambah`, 'Success!!'); |
||||||
|
} else { |
||||||
|
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const editUser = async (data) => { |
||||||
|
|
||||||
|
let urlEdit = USER_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) { |
||||||
|
getDataUser(); |
||||||
|
NotificationManager.success(`Data resource berhasil diedit`, 'Success!!'); |
||||||
|
} else { |
||||||
|
NotificationManager.error(`${result.data.message}`, `Failed!!`); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const toggleAddDialog = () => { |
||||||
|
setOpenDialog(!openDialog) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const onConfirmDelete = async () => { |
||||||
|
let url = USER_DELETE(idDelete); |
||||||
|
|
||||||
|
const result = await axios.delete(url, config) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
getDataUser() |
||||||
|
setIdDelete(0) |
||||||
|
setAlertDelete(false) |
||||||
|
NotificationManager.success(`Data user berhasil dihapus!`, 'Success!!'); |
||||||
|
} else { |
||||||
|
setIdDelete(0) |
||||||
|
setAlertDelete(false) |
||||||
|
NotificationManager.error(`Data user gagal dihapus!}`, 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const cancelDelete = () => { |
||||||
|
setAlertDelete(false) |
||||||
|
setIdDelete(0) |
||||||
|
} |
||||||
|
|
||||||
|
const RenderTable = useMemo(() => { |
||||||
|
const columns = [ |
||||||
|
{ |
||||||
|
title: t('action'), |
||||||
|
dataIndex: '', |
||||||
|
key: 'x', |
||||||
|
render: (text, record) => <> |
||||||
|
<Tooltip title={t('edit')}> |
||||||
|
<Button size="small" type="link" style={{ color: 'green' }} onClick={() => handleEdit(text)}><i className="fa fa-edit"></i></Button> |
||||||
|
</Tooltip> |
||||||
|
<Tooltip title={t('delete')}> |
||||||
|
<Button size="small" type="link" style={{ color: 'red' }} onClick={() => handleDelete(text.id)}><i className="fa fa-trash"></i></Button> |
||||||
|
</Tooltip> |
||||||
|
<Tooltip title="Set User"> |
||||||
|
<Button size="small" type="link" style={{ color: 'primary' }} onClick={() => handleSetWorker(text)}><i className="fa fa-users"></i></Button> |
||||||
|
</Tooltip> |
||||||
|
<Tooltip title="Set Menu"> |
||||||
|
<Button size="small" type="link" style={{ color: 'orange' }} onClick={() => handleSetMenu(text)}><i className="fa fa-bars"></i></Button> |
||||||
|
</Tooltip> |
||||||
|
</>, |
||||||
|
}, |
||||||
|
|
||||||
|
{ title: "Number Registration", dataIndex: 'registration_no', key: 'registration_no' }, |
||||||
|
{ title: "Name", dataIndex: 'company_name', key: 'company_name' }, |
||||||
|
{ title: 'Phone No.', dataIndex: 'phone_no', key: 'phone_no' }, |
||||||
|
{ title: 'Email', dataIndex: 'email', key: 'email' }, |
||||||
|
{ title: 'Status', dataIndex: 'is_active', key: 'is_active', render: (text, record) => <>{text && text !== false ? "Active" : 'Inactive'}</> } |
||||||
|
]; |
||||||
|
return ( |
||||||
|
<Table |
||||||
|
rowKey="id" |
||||||
|
size="small" |
||||||
|
columns={columns} |
||||||
|
dataSource={dataTable} |
||||||
|
pagination={false} |
||||||
|
/> |
||||||
|
) |
||||||
|
}, [dataTable]) |
||||||
|
|
||||||
|
return ( |
||||||
|
<div> |
||||||
|
<NotificationContainer /> |
||||||
|
<SweetAlert |
||||||
|
show={alertDelete} |
||||||
|
warning |
||||||
|
showCancel |
||||||
|
confirmBtnText="Delete" |
||||||
|
confirmBtnBsStyle="danger" |
||||||
|
title={t('deleteConfirm')} |
||||||
|
onConfirm={onConfirmDelete} |
||||||
|
onCancel={() => cancelDelete()} |
||||||
|
focusCancelBtn |
||||||
|
> |
||||||
|
{t('deleteMsg')} |
||||||
|
</SweetAlert> |
||||||
|
<DialogForm |
||||||
|
openDialog={openDialog} |
||||||
|
closeDialog={handleCloseDialog} |
||||||
|
toggleDialog={() => toggleAddDialog} |
||||||
|
typeDialog={typeDialog} |
||||||
|
dataEdit={dataEdit} |
||||||
|
clickOpenModal={clickOpenModal} |
||||||
|
divisiList={divisiList} |
||||||
|
companyID={companyID} |
||||||
|
companyNameProp={companyName} |
||||||
|
/> |
||||||
|
|
||||||
|
<Card> |
||||||
|
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}> |
||||||
|
<h4 className="capitalize">{pageName}</h4> |
||||||
|
<Row> |
||||||
|
<Col> |
||||||
|
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder='Search Company' /> |
||||||
|
</Col> |
||||||
|
<Col> |
||||||
|
<Tooltip title='Add Company'> |
||||||
|
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button> |
||||||
|
</Tooltip> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</CardHeader> |
||||||
|
<CardBody> |
||||||
|
{RenderTable} |
||||||
|
<Pagination |
||||||
|
style={{ marginTop: "25px" }} |
||||||
|
showSizeChanger |
||||||
|
onShowSizeChange={onShowSizeChange} |
||||||
|
onChange={onPagination} |
||||||
|
pageSizeOptions={["10", "25", "50"]} |
||||||
|
total={totalPage} |
||||||
|
pageSize={rowsPerPage} |
||||||
|
current={currentPage} |
||||||
|
/> |
||||||
|
</CardBody> |
||||||
|
</Card> |
||||||
|
</div> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default MasterCompany; |
@ -0,0 +1,345 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import { Link } from 'react-router-dom'; |
||||||
|
import "slick-carousel/slick/slick.css"; |
||||||
|
import "slick-carousel/slick/slick-theme.css"; |
||||||
|
import Slider from "react-slick"; |
||||||
|
import { Spin } from 'antd'; |
||||||
|
import { Checkbox } from 'antd'; |
||||||
|
import { LoadingOutlined, EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons'; |
||||||
|
import { |
||||||
|
Button, |
||||||
|
Card, |
||||||
|
CardBody, |
||||||
|
CardGroup, |
||||||
|
Col, |
||||||
|
Container, |
||||||
|
Form, |
||||||
|
Input, |
||||||
|
InputGroup, |
||||||
|
InputGroupAddon, |
||||||
|
InputGroupText, |
||||||
|
Row, |
||||||
|
UncontrolledAlert, |
||||||
|
Alert, |
||||||
|
Carousel, |
||||||
|
CarouselIndicators, |
||||||
|
CarouselCaption, |
||||||
|
CarouselItem, |
||||||
|
CarouselControl |
||||||
|
} from 'reactstrap'; |
||||||
|
import { USER_LOGIN, USER_LOGIN_V2, CALERTUSER_SEARCH, MENU_MANAGEMENT, APP_MODE } from '../../../const/ApiConst.js'; |
||||||
|
import { appConfig, reloadConstants } from '../../../const/MapConst.js'; |
||||||
|
import { APP_NAME } from '../../../const/AppConst.js' |
||||||
|
import moment from "moment" |
||||||
|
import axios from 'axios'; |
||||||
|
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||||
|
import logo_login_adw from '../../../assets/img/logo_adyawinsa.jpg' |
||||||
|
import logo_login_kit from '../../../assets/img/logo_kit.png' |
||||||
|
import logo_login_nawakara from '../../../assets/img/logo_nawakara.png' |
||||||
|
import logo_login_si from '../../../assets/img/logo-surveyor-indonesia.png' |
||||||
|
import logo_ospro from '../../../assets/img/OSPRO.png' |
||||||
|
|
||||||
|
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} spin />; |
||||||
|
|
||||||
|
const settings = { |
||||||
|
dots: true, |
||||||
|
infinite: true, |
||||||
|
speed: 500, |
||||||
|
arrows: false, |
||||||
|
autoplay: true, |
||||||
|
slidesToShow: 1, |
||||||
|
slidesToScroll: 1 |
||||||
|
}; |
||||||
|
|
||||||
|
class Login extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
this.state = { |
||||||
|
name: '', |
||||||
|
password: '', |
||||||
|
remember: '', |
||||||
|
alertVisible: false, |
||||||
|
alertMessage: '', |
||||||
|
alertColor: 'success', |
||||||
|
validate: { |
||||||
|
emailState: '', |
||||||
|
}, |
||||||
|
loader: false, |
||||||
|
type: 'password' |
||||||
|
} |
||||||
|
this.handleChange = this.handleChange.bind(this); |
||||||
|
this.showHide = this.showHide.bind(this); |
||||||
|
} |
||||||
|
showHide(e) { |
||||||
|
e.preventDefault(); |
||||||
|
e.stopPropagation(); |
||||||
|
this.setState({ |
||||||
|
type: this.state.type === 'input' ? 'password' : 'input' |
||||||
|
}) |
||||||
|
} |
||||||
|
validateEmail(e) { |
||||||
|
const emailRex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; |
||||||
|
const { validate } = this.state |
||||||
|
if (emailRex.test(e.target.value)) { |
||||||
|
validate.emailState = 'has-success' |
||||||
|
} else { |
||||||
|
validate.emailState = 'has-danger' |
||||||
|
} |
||||||
|
this.setState({ validate }) |
||||||
|
} |
||||||
|
|
||||||
|
handleChange = async (event) => { |
||||||
|
const { target } = event; |
||||||
|
const value = target.type === 'checkbox' ? target.checked : target.value; |
||||||
|
const { name } = target; |
||||||
|
await this.setState({ |
||||||
|
[name]: value, |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
getDataMenu = async (token, role_id) => { |
||||||
|
const config = { |
||||||
|
headers: |
||||||
|
{ |
||||||
|
Authorization: `Bearer ${token}`, |
||||||
|
"Content-type": `application/json` |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
let url = MENU_MANAGEMENT(role_id) |
||||||
|
const result = await axios |
||||||
|
.get(url, config) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code == 200) { |
||||||
|
let resData = result.data.data |
||||||
|
window.localStorage.setItem('menu_login', JSON.stringify(resData)); |
||||||
|
this.setState({ loader: false }) |
||||||
|
// custom redirect home after login |
||||||
|
if (role_id == 28) { |
||||||
|
this.props.history.push("/dashboard-customer/58/63"); |
||||||
|
} |
||||||
|
else { |
||||||
|
this.props.history.push("/dashboard"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
NotificationManager.error('Login Failed', 'Failed'); |
||||||
|
this.setState({ loader: false }) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
submitForm = (event) => { |
||||||
|
event.preventDefault(); |
||||||
|
this.submitFormLogin(); |
||||||
|
} |
||||||
|
|
||||||
|
submitFormLogin = async () => { |
||||||
|
this.setState({ loader: true }) |
||||||
|
const { name, password, remember } = this.state |
||||||
|
|
||||||
|
if (name === '') { |
||||||
|
NotificationManager.error('Please fill username', 'Login Failed!'); |
||||||
|
this.setState({ loader: false }) |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (password === '') { |
||||||
|
NotificationManager.error('Please fill password', 'Login Failed!'); |
||||||
|
this.setState({ loader: false }) |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
let formData = { |
||||||
|
username: name, |
||||||
|
password, |
||||||
|
remember, |
||||||
|
} |
||||||
|
|
||||||
|
const doLogin = await axios.post(USER_LOGIN_V2, formData) |
||||||
|
.then(response => response) |
||||||
|
.catch(error => { |
||||||
|
this.setState({ loader: false }); |
||||||
|
}); |
||||||
|
|
||||||
|
if (doLogin && doLogin.data && doLogin.data.code === 200) { |
||||||
|
const { access_token, data_user } = doLogin.data.data |
||||||
|
this.getDataMenu(access_token, data_user.role_id) |
||||||
|
window.localStorage.setItem('isLogin', true); |
||||||
|
window.localStorage.setItem('token', access_token); |
||||||
|
window.localStorage.setItem('user_id', data_user.id); |
||||||
|
window.localStorage.setItem('user_name', data_user.name); |
||||||
|
window.localStorage.setItem('role_id', data_user.role_id); |
||||||
|
} else { |
||||||
|
console.log("kode : ", doLogin.data.code); |
||||||
|
// NotificationManager.error('Cek username atau password anda!', 'Gagal Login!'); |
||||||
|
NotificationManager.error(doLogin.data.message, 'Login Failed!'); |
||||||
|
this.setState({ loader: false }); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
getConfigAlert = async (token, user_id) => { |
||||||
|
const config = { |
||||||
|
headers: |
||||||
|
{ |
||||||
|
Authorization: `Bearer ${token}`, |
||||||
|
"Content-type": `application/json` |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const payload = { |
||||||
|
"paging": { "start": 0, "length": -1 }, |
||||||
|
"columns": [ |
||||||
|
{ "name": "user_id", "logic_operator": "=", "value": `${user_id}`, "operator": "AND" } |
||||||
|
], |
||||||
|
"joins": [], |
||||||
|
"orders": { "columns": ["id"], "ascending": false } |
||||||
|
} |
||||||
|
|
||||||
|
const result = await axios |
||||||
|
.post(CALERTUSER_SEARCH, payload, config) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code == 200) { |
||||||
|
let resData = result.data.data |
||||||
|
let configAlert = [] |
||||||
|
resData.map((val, index) => { |
||||||
|
configAlert.push(val.config_alert_id); |
||||||
|
}); |
||||||
|
window.localStorage.setItem('userConfigAlert', configAlert.join()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
onShowAlert = (alertColor, alertMessage) => { |
||||||
|
this.setState({ alertVisible: true, alertColor: alertColor, alertMessage: alertMessage }, () => { |
||||||
|
window.setTimeout(() => { |
||||||
|
this.setState({ alertVisible: false }) |
||||||
|
}, 3000) |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
getLoginLogo = () => { |
||||||
|
return <div style={{ textAlign: 'center' }}><img style={{ width: '100%' }} src={logo_ospro} /></div> |
||||||
|
} |
||||||
|
|
||||||
|
getLoginSlider = () => { |
||||||
|
return <Slider {...settings} > |
||||||
|
<div> |
||||||
|
<img src={require('../../../assets/img/login/slide1.jpg')} className="img-avatar" /> |
||||||
|
</div> |
||||||
|
<div> |
||||||
|
<img src={require('../../../assets/img/login/slide2.jpg')} className="img-avatar" /> |
||||||
|
</div> |
||||||
|
<div> |
||||||
|
<img src={require('../../../assets/img/login/slide3.jpg')} className="img-avatar" /> |
||||||
|
</div> |
||||||
|
<div> |
||||||
|
<img src={require('../../../assets/img/login/slide4.jpg')} className="img-avatar" /> |
||||||
|
</div> |
||||||
|
</Slider> |
||||||
|
} |
||||||
|
|
||||||
|
onChecked = (e) => { |
||||||
|
this.setState({ remember: e.target.checked }) |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { name, password, remember } = this.state; |
||||||
|
const u_group = window.localStorage.getItem('u_group') |
||||||
|
if (u_group !== null) { |
||||||
|
this.props.history.push("/dashboard"); |
||||||
|
} |
||||||
|
return ( |
||||||
|
<div className="app flex-row align-items-center"> |
||||||
|
<Container> |
||||||
|
<NotificationContainer /> |
||||||
|
|
||||||
|
<Alert color={this.state.alertColor} isOpen={this.state.alertVisible} > |
||||||
|
{this.state.alertMessage} |
||||||
|
</Alert> |
||||||
|
<Row className="justify-content-center"> |
||||||
|
<Col md="7"> |
||||||
|
{this.getLoginSlider()} |
||||||
|
</Col> |
||||||
|
<Col md="5"> |
||||||
|
<div style={{ |
||||||
|
boxShadow: '1px 1px 11px 1px rgba(221,211,211,0.75)' |
||||||
|
}}> |
||||||
|
<CardGroup> |
||||||
|
<Card className="p-4"> |
||||||
|
<CardBody> |
||||||
|
<Form onSubmit={this.submitForm}> |
||||||
|
{this.getLoginLogo()} <p className="text-muted">Sign In to your account</p> <InputGroup className="mb-3"> |
||||||
|
<InputGroupAddon addonType="prepend"> |
||||||
|
<InputGroupText> |
||||||
|
<i className="icon-user"></i> |
||||||
|
</InputGroupText> |
||||||
|
</InputGroupAddon> |
||||||
|
<Input |
||||||
|
type="text" |
||||||
|
name="name" |
||||||
|
id="exampleName" |
||||||
|
placeholder="Username" |
||||||
|
value={name} |
||||||
|
onChange={(e) => { |
||||||
|
this.setState({ name: e.target.value }) |
||||||
|
}} |
||||||
|
/> |
||||||
|
</InputGroup> |
||||||
|
<InputGroup className="mb-4"> |
||||||
|
<InputGroupAddon addonType="prepend"> |
||||||
|
<InputGroupText> |
||||||
|
<i className="icon-lock"></i> |
||||||
|
</InputGroupText> |
||||||
|
</InputGroupAddon> |
||||||
|
<Input |
||||||
|
type={this.state.type} |
||||||
|
name="password" |
||||||
|
id="examplePassword" |
||||||
|
placeholder="********" |
||||||
|
value={password} |
||||||
|
onChange={(e) => this.setState({ password: e.target.value })} |
||||||
|
/> |
||||||
|
<InputGroupAddon addonType="prepend"> |
||||||
|
<InputGroupText |
||||||
|
onClick={this.showHide} |
||||||
|
> |
||||||
|
{this.state.type === 'input' ? <EyeOutlined /> : <EyeInvisibleOutlined />} |
||||||
|
|
||||||
|
</InputGroupText> |
||||||
|
</InputGroupAddon> |
||||||
|
<span className="password__show" ></span> |
||||||
|
</InputGroup> |
||||||
|
<Row> |
||||||
|
<Col xs="8"> |
||||||
|
<Checkbox checked={this.state.remember} onChange={this.onChecked}>Remember me (7 days)</Checkbox> |
||||||
|
</Col> |
||||||
|
<Col xs="4"> |
||||||
|
{this.state.loader ? ( |
||||||
|
<Spin indicator={antIcon} /> |
||||||
|
) : ( |
||||||
|
<Button onClick={() => this.submitFormLogin()} color="primary" className="px-4" >Login</Button> |
||||||
|
)} |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col className="text-right mt-5"> |
||||||
|
<Button color="link" className="px-0">Forgot password?</Button> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</Form> |
||||||
|
</CardBody> |
||||||
|
</Card> |
||||||
|
</CardGroup> |
||||||
|
</div> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</Container> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default Login; |
Loading…
Reference in new issue