root
1 year ago
13 changed files with 3790 additions and 24 deletions
@ -1,20 +1,22 @@
|
||||
FROM node:12 |
||||
# Stage 1 |
||||
FROM node:14 as build-stage |
||||
|
||||
WORKDIR /react-docker |
||||
COPY ./package*.json ./ |
||||
ENV PATH /app/node_modules/.bin:$PATH |
||||
COPY package.json . |
||||
RUN npm install |
||||
RUN npm i react@16.14.0 |
||||
RUN npm i react-scripts |
||||
RUN npm audit fix |
||||
COPY . . |
||||
|
||||
#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) |
||||
# [PROD] Use for Production |
||||
# COPY . . # uncomment prod |
||||
# Stage 2 |
||||
#FROM nginx:1.17.0-alpine |
||||
FROM nginx:alpine |
||||
|
||||
# [DEV] Live Reload |
||||
RUN mkdir -p /react-docker/src # comment for prod |
||||
RUN mkdir -p /react-docker/public # comment for prod |
||||
COPY --from=build-stage /react-docker/build /usr/share/nginx/html |
||||
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf |
||||
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,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