Browse Source

add project comments feature

pull/2/head
ardhi 2 years ago
parent
commit
f66324d918
  1. 175
      src/views/Dashboard/DashboardCustomer.js
  2. 177
      src/views/Dashboard/DashboardProject.js

175
src/views/Dashboard/DashboardCustomer.js

@ -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={{fontWeight: 'bold'}}>{name}</div>
<div style={{color: '#E80053', fontWeight: 100, fontSize: 10}}>{created_at ? moment(created_at).format('D MMMM YYYY HH:mm:ss') : '-'}</div>
<div>{comment}</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={{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>{message}</div>
<div style={{color: '#E80053', textAlign: 'right', fontWeight: 500, fontSize: 12}}>{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> </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>

177
src/views/Dashboard/DashboardProject.js

@ -1,6 +1,6 @@
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';
@ -8,6 +8,9 @@ import '../../assets/css/customscroll.css'
import moment from 'moment'; import moment from 'moment';
import { renderFormatRupiah } from '../../const/CustomFunc'; import { renderFormatRupiah } from '../../const/CustomFunc';
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 },
@ -57,11 +60,16 @@ const DashboardProject = () => {
const [totalInvoice, setTotalInvoice] = useState("10000000000"); const [totalInvoice, setTotalInvoice] = useState("10000000000");
const [cashIn, setCashIn] = useState("8000000000"); const [cashIn, setCashIn] = useState("8000000000");
const [outstandingBalance, setOutstandingBalance] = useState("2000000000"); const [outstandingBalance, setOutstandingBalance] = useState("2000000000");
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');
} }
@ -73,11 +81,111 @@ const DashboardProject = () => {
} }
}, [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,
zoom: 13 zoom: 13
}) });
setMymap(mymap); setMymap(mymap);
@ -98,16 +206,56 @@ const DashboardProject = () => {
></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>
)
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> </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>
@ -225,8 +373,10 @@ const DashboardProject = () => {
<Row> <Row>
<Col span={24}> <Col span={24}>
<div style={{maxHeight: '55vh'}}> <div style={{maxHeight: '55vh'}}>
{ activeTabIdx === 0 && <div style={{height: '52vh', width: '100%'}}>{RenderGantt}</div> } {/* { activeTabIdx === 0 && <div style={{height: '52vh', width: '100%'}}>{RenderGantt}</div> }
{ activeTabIdx === 1 && <div id="map-area" style={{height: '52vh'}} ref={mapRef}></div> } { activeTabIdx === 1 && <div id="map-area" style={{height: '52vh'}} 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> }
</div> </div>
</Col> </Col>
</Row> </Row>
@ -306,11 +456,8 @@ const DashboardProject = () => {
</Col> </Col>
</Row> </Row>
<div className='custom-scroll' style={{maxHeight: '37vh', overflow: 'auto'}}> <div className='custom-scroll' style={{maxHeight: '37vh', 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>

Loading…
Cancel
Save