|
|
@ -1,12 +1,15 @@ |
|
|
|
import React, { useEffect, useMemo, useRef, useState } from 'react'; |
|
|
|
import React, { useEffect, useMemo, useRef, useState } from 'react'; |
|
|
|
import axios from 'axios' |
|
|
|
import axios from 'axios' |
|
|
|
import { Row, Col } from 'antd'; |
|
|
|
import { Row, Col, Button, Input } from 'antd'; |
|
|
|
import { CardDashboard, CardExpenditure, CardScheduleHealthPerDivision } from '../../components/CardDashboard/CardDashboard'; |
|
|
|
import { CardDashboard, CardExpenditure, CardScheduleHealthPerDivision } from '../../components/CardDashboard/CardDashboard'; |
|
|
|
import L from 'leaflet'; |
|
|
|
import L from 'leaflet'; |
|
|
|
import { useParams } from 'react-router-dom'; |
|
|
|
import { useParams } from 'react-router-dom'; |
|
|
|
import '../../assets/css/customscroll.css' |
|
|
|
import '../../assets/css/customscroll.css' |
|
|
|
import moment from 'moment'; |
|
|
|
import moment from 'moment'; |
|
|
|
import { BASE_OSPRO } from '../../const/ApiConst'; |
|
|
|
import { BASE_OSPRO } from '../../const/ApiConst'; |
|
|
|
|
|
|
|
import { SendOutlined } from '@ant-design/icons'; |
|
|
|
|
|
|
|
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
|
|
|
|
|
|
|
const { TextArea } = Input; |
|
|
|
|
|
|
|
|
|
|
|
const styles = { |
|
|
|
const styles = { |
|
|
|
cardContainer: { backgroundColor: '#F8F8F8', margin: 2, paddingLeft: 20, paddingRight: 20, paddingTop: 10 }, |
|
|
|
cardContainer: { backgroundColor: '#F8F8F8', margin: 2, paddingLeft: 20, paddingRight: 20, paddingTop: 10 }, |
|
|
@ -26,12 +29,13 @@ const DashboardCustomer = () => { |
|
|
|
const HEADER = { |
|
|
|
const HEADER = { |
|
|
|
headers: { |
|
|
|
headers: { |
|
|
|
"Content-Type": "application/json", |
|
|
|
"Content-Type": "application/json", |
|
|
|
"Authorization": `Bearer ${token}` |
|
|
|
Authorization: `Bearer ${token}` |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
const { PROJECT_ID, GANTT_ID } = useParams(); |
|
|
|
const { PROJECT_ID, GANTT_ID } = useParams(); |
|
|
|
// const URL_GANTT = `http://103.73.125.81:8446/index.html?base_url=http://103.73.125.81:8444/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1`;
|
|
|
|
// const URL_GANTT = `http://103.73.125.81:8446/index.html?base_url=http://103.73.125.81:8444/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1`;
|
|
|
|
const URL_GANTT = `https://adw-gantt.ospro.id/index.html?base_url=${BASE_OSPRO}/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1`; |
|
|
|
const URL_GANTT = `https://adw-gantt.ospro.id/index.html?base_url=${BASE_OSPRO}/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1`; |
|
|
|
|
|
|
|
// const URL_GANTT = '';
|
|
|
|
const mapRef = useRef() |
|
|
|
const mapRef = useRef() |
|
|
|
const [projectName, setProjectName] = useState("Project Tower ABC"); |
|
|
|
const [projectName, setProjectName] = useState("Project Tower ABC"); |
|
|
|
const [customerName, setCustomerName] = useState("Jaya Gedung Group"); |
|
|
|
const [customerName, setCustomerName] = useState("Jaya Gedung Group"); |
|
|
@ -45,11 +49,16 @@ const DashboardCustomer = () => { |
|
|
|
const [activeTabCommentIdx, setActiveTabCommentIdx] = useState(0); |
|
|
|
const [activeTabCommentIdx, setActiveTabCommentIdx] = useState(0); |
|
|
|
const [planningProgress, setPlanningProgress] = useState(79); |
|
|
|
const [planningProgress, setPlanningProgress] = useState(79); |
|
|
|
const [actualProgress, setActualProgress] = useState(50); |
|
|
|
const [actualProgress, setActualProgress] = useState(50); |
|
|
|
|
|
|
|
const [comment, setComment] = useState(''); |
|
|
|
|
|
|
|
const [comments, setComments] = useState([]); |
|
|
|
|
|
|
|
const [isReadyComments, setIsReadyComments] = useState(false); |
|
|
|
|
|
|
|
const [isSendingComment, setIsSendingComment] = useState(false); |
|
|
|
|
|
|
|
const [behindTasks, setBehindTasks] = useState([]); |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
console.log('URL_GANTT', URL_GANTT); |
|
|
|
// console.log('URL_GANTT', URL_GANTT);
|
|
|
|
|
|
|
|
getComments(); |
|
|
|
|
|
|
|
getBehindTasks(); |
|
|
|
return () => { |
|
|
|
return () => { |
|
|
|
console.log('unmount RenderMap'); |
|
|
|
console.log('unmount RenderMap'); |
|
|
|
} |
|
|
|
} |
|
|
@ -61,6 +70,105 @@ const DashboardCustomer = () => { |
|
|
|
} |
|
|
|
} |
|
|
|
}, [activeTabIdx]); |
|
|
|
}, [activeTabIdx]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getComments = async () => { |
|
|
|
|
|
|
|
setIsReadyComments(false); |
|
|
|
|
|
|
|
const URL = `${BASE_OSPRO}/api/project-comment/search`; |
|
|
|
|
|
|
|
const payload = { |
|
|
|
|
|
|
|
columns: [ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
name: "project_id", |
|
|
|
|
|
|
|
logic_operator: "=", |
|
|
|
|
|
|
|
value: PROJECT_ID.toString(), |
|
|
|
|
|
|
|
operator: "AND", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
joins: [ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
name: "m_users", |
|
|
|
|
|
|
|
column_join: "sender_id", |
|
|
|
|
|
|
|
column_results: ["name", "username"], |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
orders: { columns: ["created_at"], ascending: false }, |
|
|
|
|
|
|
|
paging: { start: 0, length: -1 }, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const result = await axios.post(URL, payload, HEADER).then(res => res).catch(err => err.response) |
|
|
|
|
|
|
|
console.log('getComments', result); |
|
|
|
|
|
|
|
if (!result) { |
|
|
|
|
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
|
|
|
|
setIsReadyComments(true); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (result.status !== 200) { |
|
|
|
|
|
|
|
NotificationManager.error(`Post comment failed, ${result.data.message}`, "Failed"); |
|
|
|
|
|
|
|
setIsReadyComments(true); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
|
|
|
|
console.log(result.data.data); |
|
|
|
|
|
|
|
setComments(result.data.data); |
|
|
|
|
|
|
|
setIsReadyComments(true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handleSendComment = async () => { |
|
|
|
|
|
|
|
console.log('handleSendComment', comment); |
|
|
|
|
|
|
|
setIsSendingComment(true); |
|
|
|
|
|
|
|
if (comment === '') { |
|
|
|
|
|
|
|
NotificationManager.error("Please leave a comment before you send it.", "Failed"); |
|
|
|
|
|
|
|
setIsSendingComment(false); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const URL = `${BASE_OSPRO}/api/project-comment/add`; |
|
|
|
|
|
|
|
const payload = { |
|
|
|
|
|
|
|
"sender_id": localStorage.getItem('user_id'), |
|
|
|
|
|
|
|
"project_id": PROJECT_ID, |
|
|
|
|
|
|
|
"comment": comment |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const result = await axios.post(URL, payload, HEADER).then(res => res).catch(err => err.response) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!result) { |
|
|
|
|
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
|
|
|
|
setIsSendingComment(false); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (result.status !== 200) { |
|
|
|
|
|
|
|
NotificationManager.error(`Post comment failed, ${result.data.message}`, "Failed"); |
|
|
|
|
|
|
|
setIsSendingComment(false); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (result.status === 200) { |
|
|
|
|
|
|
|
NotificationManager.success(`Post comment success`, "Success"); |
|
|
|
|
|
|
|
resetInputComment(); |
|
|
|
|
|
|
|
getComments(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const resetInputComment = () => { |
|
|
|
|
|
|
|
setComment(''); |
|
|
|
|
|
|
|
setIsSendingComment(false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getBehindTasks = () => { |
|
|
|
|
|
|
|
setBehindTasks([ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
id: 1, |
|
|
|
|
|
|
|
name: "Tom", |
|
|
|
|
|
|
|
message: "Overdue by 5 days", |
|
|
|
|
|
|
|
division: "IT" |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
id: 1, |
|
|
|
|
|
|
|
name: "Jerry", |
|
|
|
|
|
|
|
message: "Overdue by 3 days", |
|
|
|
|
|
|
|
division: "Finance" |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
]) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const initMap = () => { |
|
|
|
const initMap = () => { |
|
|
|
let mymap = L.map('map-area', { |
|
|
|
let mymap = L.map('map-area', { |
|
|
|
center: center, |
|
|
|
center: center, |
|
|
@ -86,16 +194,56 @@ const DashboardCustomer = () => { |
|
|
|
></iframe> |
|
|
|
></iframe> |
|
|
|
), [activeTabIdx]) |
|
|
|
), [activeTabIdx]) |
|
|
|
|
|
|
|
|
|
|
|
const Comment = ({name, division, message}) => ( |
|
|
|
const Comment = ({name, comment, created_at}) => ( |
|
|
|
<div style={{backgroundColor: '#EEEEEE', border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 5, marginBottom: 5, marginRight: 2, marginLeft: 2}}> |
|
|
|
<div style={{backgroundColor: '#EEEEEE', border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 5, marginBottom: 5, marginRight: 2, marginLeft: 2}}> |
|
|
|
<div style={{fontWeight: 'bold'}}>{name}</div> |
|
|
|
<div style={{fontWeight: 'bold'}}>{name}</div> |
|
|
|
<div>{division}</div> |
|
|
|
<div style={{color: '#E80053', fontWeight: 100, fontSize: 10}}>{created_at ? moment(created_at).format('D MMMM YYYY HH:mm:ss') : '-'}</div> |
|
|
|
<div style={{color: '#E80053', textAlign: 'right', fontWeight: 500, fontSize: 12}}>{message}</div> |
|
|
|
<div>{comment}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const BehindTaskItem = ({name, message, division}) => ( |
|
|
|
|
|
|
|
<div style={{backgroundColor: '#EEEEEE', border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 5, marginBottom: 5, marginRight: 2, marginLeft: 2}}> |
|
|
|
|
|
|
|
<div style={{fontWeight: 'bold'}}>{name}</div> |
|
|
|
|
|
|
|
<div>{message}</div> |
|
|
|
|
|
|
|
<div style={{color: '#E80053', textAlign: 'right', fontWeight: 500, fontSize: 12}}>{division}</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const RenderComments = useMemo(() => { |
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
|
|
<> |
|
|
|
|
|
|
|
<div style={{padding: 5, marginBottom: 5, marginRight: 2, marginLeft: 2}}> |
|
|
|
|
|
|
|
<TextArea value={comment} onChange={(e) => setComment(e.target.value)} rows={3} placeholder="Write comment here" disabled={isSendingComment} /> |
|
|
|
|
|
|
|
<div style={{float: 'right', marginTop: -40, marginRight: 10}}> |
|
|
|
|
|
|
|
<Button title='Send' type="primary" shape="circle" icon={<SendOutlined />} size={20} onClick={handleSendComment} disabled={isSendingComment} /> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
{!isReadyComments && <div style={{color: 'grey', flex: 1, textAlign: 'center', marginTop: 50, marginBottom: 50}}>Loading comments...</div>} |
|
|
|
|
|
|
|
{isReadyComments && comments && comments.length < 1 && <div style={{flex: 1, textAlign: 'center', color: '#E80053', marginTop: 50, marginBottom: 50}}>No comments found.</div>} |
|
|
|
|
|
|
|
{comments && comments.length > 0 && comments.map((item, idx) =>
|
|
|
|
|
|
|
|
<Comment key={idx} name={item.join_first_name} comment={item.comment} created_at={item.created_at} /> |
|
|
|
|
|
|
|
)} |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</> |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
}, [comment, comments, isSendingComment, isReadyComments]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const RenderBehindTasks = useMemo(() => { |
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
{behindTasks && behindTasks.length < 1 && <div style={{flex: 1, textAlign: 'center', color: '#E80053', marginTop: 50, marginBottom: 50}}>No behind task found.</div>} |
|
|
|
|
|
|
|
{behindTasks && behindTasks.length > 0 && behindTasks.map((item, idx) =>
|
|
|
|
|
|
|
|
<BehindTaskItem key={idx} name={item.name} message={item.message} division={item.division} /> |
|
|
|
|
|
|
|
)} |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
}, [behindTasks]) |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<div style={{ marginLeft: -25, marginRight: -25 }}> |
|
|
|
<div style={{ marginLeft: -25, marginRight: -25 }}> |
|
|
|
|
|
|
|
<NotificationContainer /> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={18}> |
|
|
|
<Col span={18}> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
@ -177,7 +325,9 @@ const DashboardCustomer = () => { |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={24}> |
|
|
|
<Col span={24}> |
|
|
|
<div style={{maxHeight: '57vh'}}> |
|
|
|
<div style={{maxHeight: '57vh'}}> |
|
|
|
{ activeTabIdx === 0 && <div style={{height: '56vh', width: '100%'}}>{RenderGantt}</div> } |
|
|
|
{/* { activeTabIdx === 0 && <div style={{height: '56vh', width: '100%'}}>{RenderGantt}</div> } |
|
|
|
|
|
|
|
{ activeTabIdx === 1 && <div id="map-area" style={{height: '56vh'}} ref={mapRef}></div> } */} |
|
|
|
|
|
|
|
<div style={{height: '56vh', width: '100%', display: activeTabIdx === 0 ? 'block' : 'none'}}>{RenderGantt}</div> |
|
|
|
{ activeTabIdx === 1 && <div id="map-area" style={{height: '56vh'}} ref={mapRef}></div> } |
|
|
|
{ activeTabIdx === 1 && <div id="map-area" style={{height: '56vh'}} ref={mapRef}></div> } |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
@ -225,11 +375,8 @@ const DashboardCustomer = () => { |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<div className='custom-scroll' style={{maxHeight: '52vh', overflow: 'auto'}}> |
|
|
|
<div className='custom-scroll' style={{maxHeight: '52vh', overflow: 'auto'}}> |
|
|
|
<Comment name="Dani" division="Interior Office" message="Overdue by 3 days"/> |
|
|
|
{activeTabCommentIdx === 0 && RenderBehindTasks} |
|
|
|
<Comment name="Roland" division="Interior Office" message="Overdue by 3 days"/> |
|
|
|
{activeTabCommentIdx === 1 && RenderComments} |
|
|
|
<Comment name="John" division="Interior Office" message="Overdue by 3 days"/> |
|
|
|
|
|
|
|
<Comment name="Logan" division="Interior Office" message="Overdue by 3 days"/> |
|
|
|
|
|
|
|
<Comment name="Doe" division="Interior Office" message="Overdue by 3 days"/> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|