Commit c61dfcaf authored by Deni Rinaldi's avatar Deni Rinaldi

dashboardCAT | download unit bisnis | changePass

parent 700d2fdd
......@@ -24,6 +24,7 @@
"react": "^16.13.1",
"react-bootstrap": "^1.3.0",
"react-d3-donut": "^1.1.2",
"react-d3-speedometer": "^0.12.0",
"react-dom": "^16.13.1",
"react-dropzone": "^11.0.2",
"react-excel-renderer": "^1.1.0",
......
......@@ -84,6 +84,7 @@ const create = (baseURL = 'https://tia.eksad.com/tia-reporting-dev/public/') =>
const updateUnitBisnis = (body) => api.post('/business_unit/update_business_unit', body)
const searchUnitBisnis = (body) => api.post('/business_unit/search_business_unit', body)
const checkUploadUnitBisnis = (body) => api.post('/business_unit/check_import', body)
const uploadUnitBisnis = (body) => api.post('/business_unit/import_business_unit', body)
// Perusahaan
const getPerusahaan = () => api.get('company/get_all_company')
......@@ -104,6 +105,8 @@ const create = (baseURL = 'https://tia.eksad.com/tia-reporting-dev/public/') =>
const updateUser = (body) => api.get('user/update_user', body)
const deleteUser = (userId) => api.get(`user/delete_user/${userId}`)
const changePassword = (body) => api.post('/user/change_password', body)
//Template
const downloadTemplate = (fileName,fileType) => api.get(`attachment/download_file?fileName=${fileName}&&fileType=${fileType}`)
// ------
......@@ -150,7 +153,9 @@ const create = (baseURL = 'https://tia.eksad.com/tia-reporting-dev/public/') =>
updateUser,
deleteUser,
downloadTemplate,
checkUploadUnitBisnis
checkUploadUnitBisnis,
uploadUnitBisnis,
changePassword
}
}
......
......@@ -30,6 +30,8 @@ const Images = {
add: require('./add.svg'),
searchBlack: require('./search-black.svg'),
berhasil: require('./berhasil.svg'),
up: require('./up.svg'),
down: require('./down.svg'),
//Image
triputra: require('./triputra.png'),
......
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="23" viewBox="0 0 40 23">
<g fill="none" fill-rule="evenodd">
<path fill="#E45858" d="M26.841 0L37.507 0 37.507 10.667z" transform="matrix(1 0 0 -1 2 23)"/>
<path stroke="#E45858" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M34.848 2.849L20.991 16.234 12.912 8.435 0 20.757" transform="matrix(1 0 0 -1 2 23)"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="23" viewBox="0 0 40 23">
<g fill="none" fill-rule="evenodd">
<path fill="#7CD532" d="M26.841 0L37.507 0 37.507 10.667z" transform="translate(2)"/>
<path stroke="#7CD532" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M34.848 2.849L20.991 16.234 12.912 8.435 0 20.757" transform="translate(2)"/>
</g>
</svg>
import React, { Component } from 'react'
import { Typography, MenuItem, TextField, AppBar, Paper, Tabs, Tab } from '@material-ui/core'
import ExceutiveScoreboard from './ExceutiveScoreboard'
export default class DashboardCAT extends Component {
constructor(props) {
super(props)
this.state = {
periode: '2020',
perusahaan: 'TAP Group',
tab: 0
}
}
selectTab = (event, newEvent) => {
this.setState({ tab: newEvent })
}
render() {
const perusahaan = [
{ value: 'TAP Group', label: 'TAP Group' },
{ value: '2019', label: '2019' },
{ value: '2018', label: '2018' },
{ value: '2017', label: '2017' },
{ value: '2016', label: '2016' },
]
const periode = [
{ value: '2020', label: '2020' },
{ value: '2019', label: '2019' },
{ value: '2018', label: '2018' },
{ value: '2017', label: '2017' },
{ value: '2016', label: '2016' },
]
return (
<div style={{ height: this.props.height }}>
<div style={{ backgroundColor: '#354960', padding: 28 }}>
<Typography style={{ fontSize: '16px', color: 'white' }}>ON CHANGE CAT</Typography>
</div>
<div className="padding-20px">
<div style={{ marginTop: 20 }}>
<TextField
style={{ width: 250, }}
id="perusahaan"
select
label="Perusahaan"
value={this.state.perusahaan}
onChange={(e) => this.setState({ perusahaan: e.target.value })}
>
{perusahaan.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</TextField>
</div>
<div style={{ marginTop: 20 }}>
<TextField
style={{ width: 250, }}
id="periode"
select
label="Periode"
value={this.state.periode}
onChange={(e) => this.setState({ periode: e.target.value })}
>
{periode.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</TextField>
</div>
<Paper style={{ marginTop: 20}}>
<AppBar position="static">
<Tabs indicatorColor="primary" value={this.state.tab} onChange={this.selectTab} aria-label="simple tabs example" style={{ backgroundColor: '#354960', borderColor: 'transparent' }}>
<Tab label="Executive Scoreboard" style={{ color: '#fff', fontSize: 11 }} />
<Tab label="Strategy Map" style={{ color: '#fff', fontSize: 11 }} />
<Tab label="KPIs" style={{ color: '#fff', fontSize: 11 }} />
</Tabs>
</AppBar>
{this.state.tab == 0 ?
<ExceutiveScoreboard />
:
this.state.tab == 1 ?
<span>Testt</span>
:
<span>Test2</span>
}
</Paper>
</div>
</div>
)
}
}
import React, { Component } from 'react'
import ReactSpeedometer from "react-d3-speedometer"
import { Paper, Typography } from '@material-ui/core'
import Images from '../../assets/Images'
export default class ExceutiveScoreboard extends Component {
constructor(props) {
super(props)
this.state = {
listDummy: [
{ judul: "Overall", kpi: 0, rank: 'BS', value: 3.67, status: 'up' },
{ judul: "Financial", kpi: 5, rank: 'BS', value: 3.67, status: 'up' },
{ judul: "Customer Perspective", kpi: 2, rank: 'B', value: 3.05, status: 'down' },
{ judul: "Internal Perspective", kpi: 5, rank: 'C', value: 2.61, status: 'down' },
{ judul: "Financial", kpi: 5, rank: 'B+', value: 3.52, status: 'up' },
],
selectIndex: null
}
}
render() {
let { selectIndex } = this.state
return (
<div style={{ padding: 20 }}>
<div style={{ display: 'flex', width: '100%', justifyContent: 'space-between', flexFlow: 'wrap' }}>
{this.state.listDummy.map((item, index) => {
return (
<div style={{ padding: 10, backgroundColor: this.state.selectIndex === index ? '#6885a6' : '#fff', borderRadius: 6, paddingBottom: 20, margin: 10, boxShadow: '0 1px 4px 0 rgba(0, 0, 0, 0.25)' }} onClick={() => this.setState({ selectIndex: index })}>
<span style={{ fontSize: '17px', color: this.state.selectIndex === index ? '#fff' : '#7e8085' }}>{item.judul}</span>
<div style={{ backgroundColor: 'transparent', display: 'flex', marginTop: index === 0 ? 54 : 30, placeContent: 'center' }}>
<div>
{index != 0 ?
<div>
<span style={{ textAlign: 'center', fontSize: '24px', color: selectIndex === index ? "#fff" : '#4b4b4b' }}>{item.kpi}</span>
<span style={{ textAlign: 'center', fontSize: '11px', color: selectIndex === index ? "#fff" : '#4b4b4b' }}>KPIs</span> </div> : null}
<div style={{ backgroundColor: index === 2 ? "#7cd532" : index === 3 ? "#fcff00" : index === 4 ? "#00b440" : "#00b1f7", textAlign: 'center', width: 40, height: 21 }}>
<Typography style={{ textAlign: 'center' }}>{item.rank}</Typography>
</div>
</div>
</div>
<ReactSpeedometer
maxSegmentLabels={0}
segmentColors={[
index === 2 ? "#7cd532" : index === 3 ? "#fcff00" : index === 4 ? "#00b440" : "#00b1f7",
"#d8d8d8"
]}
needleColor={this.state.selectIndex === index ? "#fff" : '#4b4b4b'}
value={item.value}
maxValue={5}
customSegmentStops={[0, item.value, 5]}
width={200}
height={140}
ringWidth={25}
textColor={selectIndex === index ? "#fff" : '#4b4b4b'}
/>
<div style={{ backgroundColor: 'transparent', display: 'flex', marginTop: 20, placeContent: 'center' }}>
<div style={{ textAlign: '-webkit-center' }}>
{item.status === "up" ?
<img src={Images.up} /> : <img src={Images.down} />}
<Typography style={{ fontSize: 16, color: this.state.selectIndex === index ? '#fff' : '#4b4b4b' }}>vs Last Month</Typography>
</div>
</div>
</div>
)
})}
</div>
</div>
)
}
}
......@@ -58,6 +58,7 @@ export default class UnitBisnis extends Component {
let body = {
business_unit: payload
}
this.setState({ payload: body })
api.create().checkUploadUnitBisnis(body).then(response => {
// console.log(response);
let dataRow = response.data.data.map((item, index) => {
......@@ -79,6 +80,9 @@ export default class UnitBisnis extends Component {
let check = null
if (tableMeta.rowData[4] != null) {
check = tableMeta.rowData[4].findIndex((val) => val.field.includes('business_unit_name'))
if (check > -1) {
this.setState({ buttonError: true })
}
}
return (
<div style={{ display: 'flex' }}>
......@@ -101,6 +105,9 @@ export default class UnitBisnis extends Component {
let check = null
if (tableMeta.rowData[4] != null) {
check = tableMeta.rowData[4].findIndex((val) => val.field.includes('start_date'))
if (check > -1) {
this.setState({ buttonError: true })
}
}
return (
<div style={{ display: 'flex' }}>
......@@ -123,6 +130,9 @@ export default class UnitBisnis extends Component {
let check = null
if (tableMeta.rowData[4] != null) {
check = tableMeta.rowData[4].findIndex((val) => val.field.includes('end_date'))
if (check > -1) {
this.setState({ buttonError: true })
}
}
return (
<div style={{ display: 'flex' }}>
......@@ -264,6 +274,14 @@ export default class UnitBisnis extends Component {
}
}
uploadUnitBisnis() {
api.create().uploadUnitBisnis(this.state.payload).then(response => {
console.log(response)
this.getData()
this.setState({ visibleUnitBisnis: true })
})
}
render() {
const columns = [{
name: "Action",
......@@ -432,9 +450,28 @@ export default class UnitBisnis extends Component {
<span style={{ color: '#354960', fontSize: 11 }}>Batal</span>
</div>
</button>
{this.state.buttonError === true ?
<a data-tip={'Terdapat Error saat import data'} data-for="button">
<button
type="button"
onClick={() => null}
style={{}}
>
<div style={{ width: 102, height: 30, backgroundColor: '#354960', borderRadius: 5, alignItems: 'center', display: 'flex', justifyContent: 'center' }}>
<span style={{ color: '#fff', fontSize: 11 }}>Simpan</span>
</div>
</button>
</a> :
<button
type="button"
onClick={() => this.uploadUnitBisnis()}
style={{}}
>
<div style={{ width: 102, height: 30, backgroundColor: '#354960', borderRadius: 5, alignItems: 'center', display: 'flex', justifyContent: 'center' }}>
<span style={{ color: '#fff', fontSize: 11 }}>Simpan</span>
</div>
</button>}
<ReactTooltip border={true} id="button" place="top" type="light" effect="solid" />
</div>
</div>
}
......
......@@ -2,17 +2,100 @@ import React, { Component } from 'react';
import { Typography, AppBar, Tabs, Tab, TextField } from '@material-ui/core';
import HomePage from './HomePage';
import Images from '../assets/Images';
import api from '../api';
export default class Profile extends Component {
constructor(props) {
super(props)
this.state = {
tab: 0
tab: 0,
oldPassword: '',
password: '',
confirmPassword: '',
errorOldPassword: false,
errorPassword: false,
errorConfirmPassword: false,
msgOldPassword: 'Terdiri 8 karakter dengan kombinasi angka.',
msgPassword: 'Terdiri 8 karakter dengan kombinasi angka.',
msgConfirmPassword: 'Terdiri 8 karakter dengan kombinasi angka.',
}
}
selectTab = (event, newEvent) => {
this.setState({ tab: newEvent })
}
handleChange(e) {
let data = this.state
this.setState({ ...data, [e.target.name]: e.target.value })
console.log(e.target.name);
if (e.target.name == "password") {
this.setState({ errorPassword: false, msgPassword: 'Terdiri 8 karakter dengan kombinasi angka.' })
} else if (e.target.name == "confirmPassword") {
this.setState({ errorConfirmPassword: false, msgConfirmPassword: 'Terdiri 8 karakter dengan kombinasi angka.' })
} else if (e.target.name == "oldPassword") {
this.setState({ errorOldPassword: false, msgOldPassword: 'Terdiri 8 karakter dengan kombinasi angka.' })
}
}
validasi() {
if (this.state.oldPassword == "") {
this.setState({ errorOldPassword: true, msgOldPassword: 'Kata sandi lama harus diisi!' })
} else if (this.state.oldPassword.length < 8) {
this.setState({ errorOldPassword: true, msgOldPassword: 'Kata sandi lama minimal 8 karakter!' })
} else if (this.isEmail(this.state.oldPassword)) {
this.setState({ errorOldPassword: true, msgOldPassword: 'Format kata sandi lama tidak boleh menggunakan email!' })
} else if (!this.isRegex(this.state.oldPassword)) {
this.setState({ errorOldPassword: true, msgOldPassword: 'Kata sandi lama harus berupa kombinasi karakter, huruf dan angka!' })
} else if (this.state.password.trim() == "") {
this.setState({ errorPassword: true, msgPassword: 'Kata sandi baru harus diisi!' })
} else if (this.state.password.length < 8) {
this.setState({ errorPassword: true, msgPassword: 'Kata sandi baru minimal 8 karakter!' })
} else if (this.isEmail(this.state.password)) {
this.setState({ errorPassword: true, msgPassword: 'Format kata sandi baru tidak boleh menggunakan email!' })
} else if (!this.isRegex(this.state.password)) {
this.setState({ errorPassword: true, msgPassword: 'Kata sandi baru harus berupa kombinasi karakter, huruf dan angka!' })
} else if (this.state.confirmPassword.trim() == "") {
this.setState({ errorConfirmPassword: true, msgConfirmPassword: 'Konfirmasi kata sandi harus diisi!' })
} else if (this.state.confirmPassword.length < 8) {
this.setState({ errorConfirmPassword: true, msgConfirmPassword: 'Konfirmasi kata sandi minimal 8 karakter!' })
} else if (this.isEmail(this.state.confirmPassword)) {
this.setState({ errorConfirmPassword: true, msgConfirmPassword: 'Format konfirmasi kata sandi tidak boleh menggunakan email!' })
} else if (!this.isRegex(this.state.confirmPassword)) {
this.setState({ errorConfirmPassword: true, msgConfirmPassword: 'Konfirmasi kata sandi harus berupa kombinasi karakter, huruf dan angka!' })
} else if (this.state.password !== this.state.confirmPassword) {
this.setState({ errorConfirmPassword: true, msgConfirmPassword: 'Konfirmasi kata sandi harus sama dengan kata sandi baru!' })
} else {
this.confirmPassword()
}
}
confirmPassword(){
let body = {
"old_password": this.state.oldPassword,
"new_password": this.state.password,
"confirm_password": this.state.confirmPassword
}
api.create().changePassword(body).then(response => {
console.log(response);
if (response.data.status === "success") {
this.setState({ oldPassword: "", password: "", confirmPassword: ""})
alert(response.data.message)
} else {
alert(response.data.message)
}
})
}
isRegex(value) {
// const re = /^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$/;
const re = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{1,}$/;
return re.test(String(value));
}
isEmail(email) {
const re = /^(([^<>()\[\]\\.,;:\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,}))$/;
return re.test(String(email).toLowerCase());
}
render() {
return (
<div style={{ height: this.props.height, backgroundColor: '#f8f8f8', marginBottom: 100, minHeight: 1000 }}>
......@@ -37,34 +120,58 @@ export default class Profile extends Component {
</div>
<div style={{ padding: 20, justifyContent: 'space-between' }}>
<TextField
style={{ width: '100%'}}
style={{ width: '100%' }}
inputProps={{ style: { fontSize: 11 } }}
id="filled-required"
name={"oldPassword"}
label="Kata Sandi Saat Ini"
defaultValue=""
value={this.state.oldPassword}
variant="outlined"
onChange={(password) => {
this.handleChange(password)
}}
error={this.state.errorOldPassword}
helperText={<Typography style={{ fontSize: 9, marginTop: 4, fontFamily: 'Nunito Sans, sans-serif' }}>{this.state.msgOldPassword}</Typography>}
/>
<TextField
style={{ width: '100%', marginTop: 20 }}
inputProps={{ style: { fontSize: 11 } }}
id="filled-required"
label="Kata Sandi Baru"
defaultValue=""
name={"password"}
value={this.state.password}
onChange={(password) => {
this.handleChange(password)
}}
error={this.state.errorPassword}
helperText={<Typography style={{ fontSize: 9, marginTop: 4, fontFamily: 'Nunito Sans, sans-serif' }}>{this.state.msgPassword}</Typography>}
variant="outlined"
/>
<TextField
style={{ width: '100%', marginTop: 20}}
style={{ width: '100%', marginTop: 20 }}
inputProps={{ style: { fontSize: 11 } }}
id="filled-required"
label="Konfirmasi Kata Sandi Baru"
defaultValue=""
name={"confirmPassword"}
value={this.state.confirmPassword}
onChange={(confirmPassword) => {
this.handleChange(confirmPassword)
}}
variant="outlined"
error={this.state.errorConfirmPassword}
helperText={<Typography style={{ fontSize: 9, marginTop: 4, fontFamily: 'Nunito Sans, sans-serif' }}>{this.state.msgConfirmPassword}</Typography>}
/>
</div>
<div style={{width: '100%', backgroundColor: '#f5f5f5', height: 43, display: 'flex', justifyContent: 'flex-end', padding: 10, borderColor: 'rgba(0, 0, 0, 0.25)', borderWidth: .2, borderStyle: 'dotted'}}>
<div style={{backgroundColor: '#354960', textAlign: 'center', height: 25, width: 64, borderRadius: 3}}>
<span style={{color: 'white', fontSize: 11}}>Simpan</span>
<div style={{ width: '100%', backgroundColor: '#f5f5f5', height: 43, display: 'flex', justifyContent: 'flex-end', padding: 10, borderColor: 'rgba(0, 0, 0, 0.25)', borderWidth: .2, borderStyle: 'dotted' }}>
<button
type="button"
onClick={() => this.validasi()}
style={{}}
>
<div style={{ backgroundColor: '#354960', textAlign: 'center', height: 25, width: 64, borderRadius: 3 }}>
<span style={{ color: 'white', fontSize: 11 }}>Simpan</span>
</div>
</button>
</div>
</div>
</div> :
......@@ -74,21 +181,21 @@ export default class Profile extends Component {
<Typography style={{ fontSize: '13px', color: 'white', fontWeight: 'bold' }}>Otorisasi Perusahaan</Typography>
</div>
<div style={{ padding: 20 }}>
<div style={{ display: 'flex'}}>
<img src={Images.check} style={{ marginRight: 10}}/>
<Typography style={{fontSize: 14, opacity: .5, color: '#4b4b4b'}}>Agro PersadaTriputra </Typography>
<div style={{ display: 'flex' }}>
<img src={Images.check} style={{ marginRight: 10 }} />
<Typography style={{ fontSize: 14, opacity: .5, color: '#4b4b4b' }}>Agro PersadaTriputra </Typography>
</div>
<div style={{ display: 'flex', marginTop: 20}}>
<img src={Images.check} style={{ marginRight: 10}}/>
<Typography style={{fontSize: 14, opacity: .5, color: '#4b4b4b'}}>Dharma Group</Typography>
<div style={{ display: 'flex', marginTop: 20 }}>
<img src={Images.check} style={{ marginRight: 10 }} />
<Typography style={{ fontSize: 14, opacity: .5, color: '#4b4b4b' }}>Dharma Group</Typography>
</div>
<div style={{ display: 'flex', marginTop: 20, paddingLeft: 20}}>
<img src={Images.check} style={{ marginRight: 10}}/>
<Typography style={{fontSize: 14, opacity: .5, color: '#4b4b4b'}}>Dharma Polimetal</Typography>
<div style={{ display: 'flex', marginTop: 20, paddingLeft: 20 }}>
<img src={Images.check} style={{ marginRight: 10 }} />
<Typography style={{ fontSize: 14, opacity: .5, color: '#4b4b4b' }}>Dharma Polimetal</Typography>
</div>
<div style={{ display: 'flex', marginTop: 20, paddingLeft: 20}}>
<img src={Images.check} style={{ marginRight: 10}}/>
<Typography style={{fontSize: 14, opacity: .5, color: '#4b4b4b'}}>Dharma Poliplast</Typography>
<div style={{ display: 'flex', marginTop: 20, paddingLeft: 20 }}>
<img src={Images.check} style={{ marginRight: 10 }} />
<Typography style={{ fontSize: 14, opacity: .5, color: '#4b4b4b' }}>Dharma Poliplast</Typography>
</div>
</div>
</div>
......
......@@ -33,7 +33,7 @@ const arraySide = [
{
img: 'beranda',
label: 'Dashboard CAT',
path: 'beranda',
path: 'dashboard-cat',
},
{
img: 'beranda',
......
......@@ -11,6 +11,7 @@ import Perusahaan from '../container/MasterData/Perusahaan/Perusahaan';
import UnitBisnis from '../container/MasterData/UnitBisnis'
import ItemLaporan from '../container/MasterData/ItemLaporan'
import Parameter from '../container/MasterData/Parameter/Parameter'
import DashboardCAT from '../container/Laporan/DashboardCAT'
const routes = [
{
......@@ -53,6 +54,10 @@ const routes = [
path: "/home/parameter",
main: Parameter
},
{
path: "/home/dashboard-cat",
main: DashboardCAT
},
{
path: "*",
main: screen404
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment