Skip to content

Commit

Permalink
Improve comment section
Browse files Browse the repository at this point in the history
  • Loading branch information
blagoslav-mihaylov committed Apr 3, 2021
1 parent 48c5ed8 commit 7f42ecd
Show file tree
Hide file tree
Showing 7 changed files with 489 additions and 83 deletions.
103 changes: 103 additions & 0 deletions src/components/Util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
const format = function(number, n, x, s, c) {
var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\D' : '$') + ')',
num = parseFloat(number).toFixed(Math.max(0, ~~n));

return (c ? num.replace('.', c) : num).replace(new RegExp(re, 'g'), '$&' + (s || ','));
};

const formatLv = function(number) {
return format(number, 2, 3, ' ', ',');
};

const formatPop = function(number) {
return format(Math.floor(number), 0, 3, ' ', ',');
}

const pad = num => {
var s = String(num);
while (s.length < 2) {s = "0" + s;}
return s;
};

const month = monthStr => {
switch(monthStr) {
case 0: return 'януари'; break;
case 1: return 'февруари'; break;
case 2: return 'март'; break;
case 3: return 'април'; break;
case 4: return 'май'; break;
case 5: return 'юни'; break;
case 6: return 'юли'; break;
case 7: return 'август'; break;
case 8: return 'септември'; break;
case 9: return 'октомври'; break;
case 10: return 'ноември'; break;
case 11: return 'декември'; break;
}
};

const formatDay = d => {
if(d >= 10 && d <= 20)
return d + '-ти';

switch(d%10) {
case 1: return d + '-ви'; break;
case 2: return d + '-ри'; break;
case 7: case 8: return d + '-ми'; break;
default: return d + '-ти'; break;
}
};

const formatDate = dateTime => {
const date = new Date(dateTime);

return formatDay(date.getDate()) + ' ' +
month(date.getMonth()) + ' '+
date.getFullYear();
};

const formatTime = dateTime => {
const date = new Date(dateTime);
return pad(date.getHours()) + ':' +
pad(date.getMinutes());
};

const formatDateTime = dateTime => {
return formatTime(dateTime) + ' ' + formatDateShort(dateTime);

};

const formatSecs = secs => {
return pad(Math.floor(secs / 60)) + ':' + pad(secs % 60);
};

const formatDateShort = dateTime => {
const date = new Date(dateTime);

return pad(date.getDate()) + '.' +
pad(date.getMonth()+1) + '.' +
pad(date.getFullYear());
}

const checkPaths = (path1, path2) => {
if(!path1 || !path2) return false;

if(path1[path1.length - 1] !== '/')
path1 = path1 + '/';
if(path2[path2.length - 1] !== '/')
path2 = path2 + '/';

return path1 === path2;
}

module.exports = {
formatLv,
formatPop,
formatDate,
formatDateShort,
formatDateTime,
formatTime,
formatSecs,
format,
checkPaths,
};
5 changes: 4 additions & 1 deletion src/components/modules/Modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import ProtocolDetails from './protocols/ProtocolDetails';

import ViolationList from './violations/ViolationList';
import ViolationDetails from './violations/ViolationDetails';
import AllComments from './violations/AllComments';

import styled from 'styled-components';
import Sections from './Sections';
Expand All @@ -36,7 +37,8 @@ const ContentHalf = styled.div`

export const ContentPanel = styled.div`
background-color: white;
margin: 30px 15%;
margin: 30px auto;
max-width: 800px;
border-radius: 15px;
//box-shadow: 0px 0px 5px #aaa;
border: 1px solid #eee;
Expand All @@ -60,6 +62,7 @@ export default props => {
<Route path='/sections' component={Sections}/>
<Route path='/protocol/:protocol' component={ProtocolDetails}/>
<Route path='/protocols' component={ProtocolsHome}/>
<Route path='/violation/:violation/comments' component={AllComments}/>
<Route path='/violation/:violation' component={ViolationDetails}/>
<Route path='/violations' component={ViolationList}/>
<Route path='/users' component={Admin}/>
Expand Down
129 changes: 129 additions & 0 deletions src/components/modules/violations/AllComments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import React, { useState, useEffect, useContext } from 'react';

import { Link, useLocation, useParams, useHistory } from 'react-router-dom';

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faChevronLeft, faChevronRight, faFastForward, faFastBackward } from '@fortawesome/free-solid-svg-icons';

import Loading from '../../layout/Loading';
import { ContentPanel } from '../Modules';

import { AuthContext } from '../../App';

import CommentForm from './CommentForm';
import { PaginationLinks } from './CommentSection';
import Comment from './Comment';

const useQuery = () => {
return new URLSearchParams(useLocation().search);
}

import styled from 'styled-components';

const BackButton = styled(Link)`
cursor: pointer;
border: none;
border-radius: 6px;
background: none;
margin-right: 5px;
font-size: 48px;
color: black;
padding: 5px;
&:hover {
background-color: #eee;
}
`;

export default props => {
const [data, setData] = useState(null);
const query = useQuery();
const { violation } = useParams();
const history = useHistory();

const { authGet } = useContext(AuthContext);

useEffect(() => {
let url = `/violations/${violation}/comments`;
const page = query.get("page");
const limit = query.get("limit");

if(page || limit) url += '?';

if(page) url += `page=${page}`;
if(limit) url += `limit=${limit}`;

authGet(url).then(res => {
setData(res.data);
});
}, [query.get("page")]);

const renderLinks = () => {
const firstAvail = data.meta.currentPage !== 1;
const lastAvail = data.meta.currentPage !== data.meta.totalPages;
const nextAvail = data.links.next;
const prevAvail = data.links.previous;

const nextPage = data.meta.currentPage + 1;
const prevPage = data.meta.currentPage - 1;

return (
<PaginationLinks>
<Link className={firstAvail? '' : 'disabled'} to={`/violation/${violation}/comments?page=${1}&limit=20`}>
<FontAwesomeIcon icon={faFastBackward}/> Първа
</Link>
<Link className={prevAvail? '' : 'disabled'} to={`/violation/${violation}/comments?page=${prevPage}&limit=20`}>
<FontAwesomeIcon icon={faChevronLeft}/> Предишна
</Link>
<div style={{margin: '0 5px', display: 'inline-block', color: '#444', width: '60px'}}>
{data.meta.currentPage} / {data.meta.totalPages}
</div>
<Link className={nextAvail? '' : 'disabled'} to={`/violation/${violation}/comments?page=${nextPage}&limit=20`}>
Следваща <FontAwesomeIcon icon={faChevronRight}/>
</Link>
<Link className={lastAvail? '' : 'disabled'} to={`/violation/${violation}/comments?page=${data.meta.totalPages}&limit=20`}>
Последна <FontAwesomeIcon icon={faFastForward}/>
</Link>
</PaginationLinks>
);
};

const newComment = comment => {
if(!query.get("page") || query.get("page").toString() === '1') {
if(data.items.length < data.meta.itemsPerPage) {
setData({...data, meta: {...data.meta, totalItems: data.meta.totalItems + 1}, items: [comment, ...data.items]});
} else if(data.meta.totalItems === data.meta.itemsPerPage) {
history.push(`/violation/${violation}/comments?page=1&limit=20`);
} else {
let newItems = [comment, ...data.items].slice(0, data.meta.itemsPerPage);
setData({...data, meta: {...data.meta, totalItems: data.meta.totalItems + 1}, items: newItems});
}
} else {
history.push(`/violation/${violation}/comments?page=1&limit=20`);
}
};

return (
<ContentPanel>
<h1>
<BackButton to={`/violation/${violation}`}><FontAwesomeIcon icon={faChevronLeft}/></BackButton>
<span style={{verticalAlign: 'top', marginTop: '10px', display: 'inline-block'}}>
Всички коментари
{!data? null : ` (${data.meta.totalItems})`}
</span>
</h1>
<hr/>
<CommentForm newComment={newComment}/>
{
!data? <Loading/> : [
data.meta.totalPages > 1? renderLinks() : null,
data.items.map(comment => [
<Comment comment={comment}/>,
<hr/>
]),
data.meta.totalPages > 1? renderLinks() : null,
]
}
</ContentPanel>
);
};
62 changes: 62 additions & 0 deletions src/components/modules/violations/Comment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';

import styled from 'styled-components';

import { formatTime, formatDateShort } from '../../Util';

export const CommentStyle = styled.div`
width: 100%;
h1 {
font-weight: normal;
font-size: 22px;
margin: 5px 0;
color: #555;
}
h2 {
font-weight: normal;
font-size: 16px;
margin: 5px 0;
color: #bbb;
}
p {
color: #333;
}
.comment-type {
color: #888;
border: 3px solid #888;
border-radius: 10px;
font-size: 12px;
padding: 5px;
font-weight: bold;
vertical-align: top;
display: inline-block;
margin-left: 10px;
margin-top: -2px;
}
`;

export default props => {
console.log(props.comment);

const formatCommentType = commentType => {
switch(commentType) {
case 'internal': return 'Вътрешен'; break;
default: return 'Вътрешен'; break;
}
};

return (
<CommentStyle>
<h1>
{props.comment.author.firstName} {props.comment.author.lastName}
<span className='comment-type'>{formatCommentType(props.comment.type)}</span>
</h1>
<h2>{formatTime(props.comment.createdAt)}{formatDateShort(props.comment.createdAt)}</h2>
<p>{props.comment.text}</p>
</CommentStyle>
);
};
Loading

0 comments on commit 7f42ecd

Please sign in to comment.