Permalink
Browse files

Add 'comments' functionality

  • Loading branch information...
marcomontalbano committed Dec 20, 2018
1 parent 35dff60 commit 92f84bc0b3d18fc982180759dcab92e9973a6252

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -1,6 +1,6 @@
{
"name": "technology-radar",
"version": "3.1.2",
"version": "4.0.0",
"description": "Technology Radar is a tool that helps organizations to monitor their own discoveries. Keep track of your technologies according to your previous successes and failures.",
"main": "index.js",
"homepage": ".",
@@ -4,15 +4,18 @@ import SearchActions from './actions/SearchActions';

import Item from './class/Item';
import Category from './class/Category';
import Comment from './class/Comment';

class Api {
constructor() {
this.spreadsheetId = process.env.REACT_APP_SPREADSHEET_ID;
this.urls = {
// items: 'mock/items.json',
// categories: 'mock/categories.json',
// comments: 'mock/comments.json',
items: `https://spreadsheets.google.com/feeds/list/${this.spreadsheetId}/1/public/values?alt=json-in-script&callback={1}`,
categories: `https://spreadsheets.google.com/feeds/list/${this.spreadsheetId}/2/public/values?alt=json-in-script&callback={1}`,
comments: `https://spreadsheets.google.com/feeds/list/${this.spreadsheetId}/3/public/values?alt=json-in-script&callback={1}`,
};
}

@@ -24,18 +27,32 @@ class Api {
return;
}

(new ItemsLoader()).load(this.urls.categories, Category, (categories) => {
const getCategoryByName = (name) => {
return _.find(categories, (o) => { return o.name === name });
Promise.all([
ItemsLoader.load(this.urls.categories, Category),
ItemsLoader.load(this.urls.comments, Comment)
]).then(([categories, comments]) => {

const filterByName = (list, name) => {
return _.filter(list, (o) => { return o.name === name });
};

(new ItemsLoader()).load(this.urls.items, Item, (items) => {
SearchActions.changeItems(items);
}, (item) => {
ItemsLoader.load(this.urls.items, Item, (item) => {
const result = item;

// decorator
result.category = getCategoryByName(item.category);

result.category = filterByName(categories, item.category)[0] || {
name: 'uncategorized', color: '#e0e0e0'
};

result.comments = filterByName(comments, item.name).sort(function compare(a, b) {
return (new Date(b.date)) - (new Date(a.date)); // most recent on top
});

return result;
}).then((items) => {
SearchActions.changeItems(items);
window.items = items;
});
});
}
@@ -0,0 +1,10 @@
export default class Comment {
constructor({ date = '', name = '', author = '', message = '', prevstatus = '', nextstatus = '' }) {
this.date = date;
this.name = name;
this.author = author;
this.message = message;
this.prevstatus = prevstatus;
this.nextstatus = nextstatus;
}
}
@@ -1,7 +1,7 @@
import _ from 'lodash';

export default class Item {
constructor({ name = '', description = '', category = '', status = '', url = '', tags = '' }) {
constructor({ name = '', description = '', category = '', status = '', url = '', tags = '', comments = '' }) {
this.name = name;
this.description = description;
this.category = category;
@@ -10,5 +10,6 @@ export default class Item {
return tag.trim();
}) : [];
this.url = url;
this.comments = comments || [];
}
}
@@ -4,38 +4,35 @@ import mime from 'rest/interceptor/mime';

const client = rest.wrap(mime);

export default class ItemsLoader {
constructor() {
this.items = [];
}

load(url, Obj, callback, decorator) {
if (_.isEmpty(this.items)) {
switch (true) {
export default {
load: (url, Obj, decorator) => {
switch (true) {
case (url.indexOf('https://spreadsheets.google.com/feeds/list/') === 0):
this.googleSpreadsheets(url, Obj, callback, decorator);
break;
return googleSpreadsheets(url, Obj, decorator);
default:
this.json(url, Obj, callback, decorator);
break;
}
} else {
callback(this.items);
return json(url, Obj, decorator);
}
}
}


json(url, Obj, callback, decorator) {
function json(url, Obj, decorator) {
return new Promise((resolve, reject) => {
let items = [];
const decorate = decorator || ((item) => { return item });
client(url).then((response) => {
_.map(response.entity, (elm) => {
const item = decorate(elm);
this.items.push(new Obj(item));
items.push(new Obj(item));
});
callback(this.items);
resolve(items);
});
}
});
}

googleSpreadsheets(url, Obj, callback, decorator) {
function googleSpreadsheets(url, Obj, decorator) {
return new Promise((resolve, reject) => {
let items = [];
const decorate = decorator || ((item) => { return item });
const random = () => {
return Math.round(Math.random() * 100);
@@ -64,13 +61,13 @@ export default class ItemsLoader {

_.map(jsonData.feed.entry, (entry) => {
const item = convertEntryToItem(entry);
this.items.push(item);
items.push(item);
});

callback(this.items);
resolve(items);
});

document.head.appendChild(script);
}
}
});
}
@@ -37,10 +37,42 @@ export default class ItemComponent extends Component {
};
}

tags() {
return _.map(this.props.item.tags, (tag, key) => (
<span key={key}><div className="uk-label" style={this.labelStyle}>{tag}</div>&nbsp;</span>
renderLabel(text) {
return <div className="uk-label" style={this.labelStyle}>{text}</div>
}

renderTags(showContainer) {
const tags = _.map(this.props.item.tags, (tag, key) => (
<span key={key}>{this.renderLabel(tag)}&nbsp;</span>
));

return _.isEmpty(tags) === false && showContainer ? (
<div className="uk-modal-footer">{tags}</div>
) : tags;
}

renderComments() {
const comments = _.map(this.props.item.comments, (comment, key) => {
const changedStatus = _.isEmpty(comment.prevstatus) && _.isEmpty(comment.nextstatus) ? '' : (<div>{this.renderLabel(comment.prevstatus)} <i className="fa fa-arrow-right" aria-hidden="true"></i> {this.renderLabel(comment.nextstatus)}</div>);
return (
<li key={key}>
<article className="uk-comment">
<div className="uk-comment-body">
<div><small>{comment.date}</small></div>
<div className="uk-text-bold uk-text-primary">{comment.author}</div>
{changedStatus}
<div className="uk-margin-small-top">{comment.message}</div>
</div>
</article>
</li>
)
});

return _.isEmpty(comments) === false ? (
<div className="uk-modal-footer uk-padding-small">
<ul className="uk-comment-list">{comments}</ul>
</div>
) : comments;
}

renderCard() {
@@ -52,7 +84,7 @@ export default class ItemComponent extends Component {
<p className="uk-card-description">{this.props.item.description}</p>
</div>
<div className="uk-card-footer">
{this.tags()}
{this.renderTags(false)}
</div>
</div>
);
@@ -73,9 +105,8 @@ export default class ItemComponent extends Component {
<p className="uk-modal-description">{this.props.item.description}</p>
<a target="_blank" rel="noopener noreferrer" {...this.props.item.url ? { href: this.props.item.url } : {}}><i className="fa fa-globe"></i>website</a>
</div>
<div className="uk-modal-footer">
{this.tags()}
</div>
{this.renderTags(true)}
{this.renderComments()}
</div>
</div>
);
@@ -55,7 +55,7 @@ const updateResultItems = () => {
const queryRegExp = new RegExp(memo.query, 'i');

const items = _.filter(memo.items, (item) => {
let result = queryRegExp.test(item.name) || queryRegExp.test(item.description);
let result = queryRegExp.test(item.name) || queryRegExp.test(item.description) || item.comments.filter(c => queryRegExp.test(c.message)).length > 0;
result = result && (memo.categories.length === 0 ? true : memo.categories.indexOf(item.category.name) >= 0);
result = result && (memo.statuses.length === 0 ? true : memo.statuses.indexOf(item.status) >= 0);
result = result && (memo.tags.length === 0 ? true : _.filter(memo.tags, (tag) => { return item.tags.indexOf(tag) >= 0 }).length > 0);
@@ -10,5 +10,6 @@
@import 'components/navbar';
@import 'components/modal';
@import 'components/card';
@import 'components/comment';
@import 'components/offcanvas';
@import 'components/view';
@@ -0,0 +1,17 @@
.hook-comment-misc() {
.uk-comment-list > :nth-child(n+2) {
margin-top: 15px;
}
}

.hook-comment-body() {
background-color: #f8f8f8;
border-radius: 18px;
padding: 12px 16px;

i {
vertical-align: middle;
font-size: 10px;
margin: 0 4px;
}
}

0 comments on commit 92f84bc

Please sign in to comment.