display tags in frontend

This commit is contained in:
Ivan Diaz 2019-02-22 18:26:06 -03:00
parent fad0e8eafb
commit 5bf8ff94bc
7 changed files with 131 additions and 56 deletions

View File

@ -1,5 +1,6 @@
import React from 'react';
import _ from 'lodash';
import {connect} from "react-redux";
import i18n from 'lib-app/i18n';
import DateTransformer from 'lib-core/date-transformer';
@ -11,6 +12,7 @@ import Button from 'core-components/button';
import Tooltip from 'core-components/tooltip';
import Icon from 'core-components/icon';
import Checkbox from 'core-components/checkbox';
import Tag from 'core-components/tag';
class TicketList extends React.Component {
static propTypes = {
@ -182,9 +184,16 @@ class TicketList extends React.Component {
</Tooltip>
),
title: (
<Button className="ticket-list__title-link" type="clean" route={{to: this.props.ticketPath + ticket.ticketNumber}}>
{titleText}
</Button>
<div>
<Button className="ticket-list__title-link" type="clean" route={{to: this.props.ticketPath + ticket.ticketNumber}}>
{titleText}
</Button>
{ticket.tags.map((tagName,index) => {
let tag = _.find(this.props.tags, {name:tagName});
return <Tag size='small' name={tag && tag.name} color={tag && tag.color} key={index} />
})}
</div>
),
priority: this.getTicketPriority(ticket.priority),
department: ticket.department.name,
@ -257,5 +266,8 @@ class TicketList extends React.Component {
}
}
export default TicketList;
export default connect((store) => {
return {
tags: store.config['tags']
};
})(TicketList);

View File

@ -22,6 +22,8 @@ import Icon from 'core-components/icon';
import TextEditor from 'core-components/text-editor';
import InfoTooltip from 'core-components/info-tooltip';
import DepartmentDropdown from 'app-components/department-dropdown';
import TagSelector from 'core-components/tag-selector';
import Tag from 'core-components/tag';
class TicketViewer extends React.Component {
static propTypes = {
@ -36,10 +38,12 @@ class TicketViewer extends React.Component {
userId: React.PropTypes.number,
userStaff: React.PropTypes.bool,
userDepartments: React.PropTypes.array,
userLevel: React.PropTypes.number
userLevel: React.PropTypes.number,
tags: React.PropTypes.array
};
static defaultProps = {
tags: [],
editable: false,
ticket: {
author: {},
@ -63,6 +67,7 @@ class TicketViewer extends React.Component {
render() {
const ticket = this.props.ticket;
console.log('tickett',ticket)
return (
<div className="ticket-viewer">
@ -105,7 +110,7 @@ class TicketViewer extends React.Component {
<div className="ticket-viewer__info-row-header row">
<div className="col-md-4">{i18n('DEPARTMENT')}</div>
<div className="col-md-4">{i18n('AUTHOR')}</div>
<div className="col-md-4">{i18n('DATE')}</div>
<div className="col-md-4">{i18n('TAGS')}</div>
</div>
<div className="ticket-viewer__info-row-values row">
<div className="col-md-4">
@ -115,7 +120,7 @@ class TicketViewer extends React.Component {
onChange={this.onDepartmentDropdownChanged.bind(this)} />
</div>
<div className="col-md-4">{ticket.author.name}</div>
<div className="col-md-4">{DateTransformer.transformToString(ticket.date)}</div>
<div className="col-md-4"> <TagSelector items={this.props.tags} values={this.props.ticket.tags} onRemoveClick={this.removeTag.bind(this)} onTagSelected={this.addTag.bind(this)}/></div>
</div>
<div className="ticket-viewer__info-row-header row">
<div className="col-md-4">{i18n('PRIORITY')}</div>
@ -153,12 +158,15 @@ class TicketViewer extends React.Component {
<div className="ticket-viewer__info-row-header row">
<div className="ticket-viewer__department col-md-4">{i18n('DEPARTMENT')}</div>
<div className="ticket-viewer__author col-md-4">{i18n('AUTHOR')}</div>
<div className="ticket-viewer__date col-md-4">{i18n('DATE')}</div>
<div className="ticket-viewer__date col-md-4">{i18n('TAGS')}</div>
</div>
<div className="ticket-viewer__info-row-values row">
<div className="ticket-viewer__department col-md-4">{ticket.department.name}</div>
<div className="ticket-viewer__author col-md-4">{ticket.author.name}</div>
<div className="ticket-viewer__date col-md-4">{DateTransformer.transformToString(ticket.date, false)}</div>
<div className="col-md-4">{ticket.tags.length ? ticket.tags.map((tagName,index) => {
let tag = _.find(this.props.tags, {name:tagName});
return <Tag name={tag && tag.name} color={tag && tag.color} key={index} />
}) : i18n('NONE')}</div>
</div>
<div className="ticket-viewer__info-row-header row">
<div className="ticket-viewer__department col-md-4">{i18n('PRIORITY')}</div>
@ -412,7 +420,25 @@ class TicketViewer extends React.Component {
}
}).then(this.onTicketModification.bind(this));
}
addTag(tag) {
API.call({
path: '/ticket/add-tag',
data: {
ticketNumber: this.props.ticket.ticketNumber,
tagId: tag
}
}).then(this.onTicketModification.bind(this))
}
removeTag(tag) {
API.call({
path: '/ticket/remove-tag',
data: {
ticketNumber: this.props.ticket.ticketNumber,
tagId: tag
}
}).then(this.onTicketModification.bind(this))
}
onCustomResponsesChanged({index}) {
let replaceContentWithCustomResponse = () => {
this.setState({
@ -515,6 +541,7 @@ export default connect((store) => {
staffMembersLoaded: store.adminData.staffMembersLoaded,
allowAttachments: store.config['allow-attachments'],
userSystemEnabled: store.config['user-system-enabled'],
userLevel: store.session.userLevel
userLevel: store.session.userLevel,
tags: store.config['tags']
};
})(TicketViewer);

View File

@ -2,6 +2,7 @@ import React from 'react';
import _ from 'lodash';
import Icon from 'core-components/icon';
import DropDown from 'core-components/drop-down';
import Tag from 'core-components/tag';
class TagSelector extends React.Component {
@ -32,14 +33,8 @@ class TagSelector extends React.Component {
renderSelectedTag(item,index) {
return (
<div className="tag-selector__selected-tag" style={{backgroundColor:item.color}} onClick={event => event.stopPropagation()} key={index}>
<span className="tag-selector__selected-tag-name">{item.name}</span>
<span onClick={this.onRemoveClick.bind(this,item.name)} className="tag-selector__selected-tag-remove" >
<Icon name="times-circle" size="small"/>
</span>
</div>
);
return <Tag name={item.name} color={item.color} showDeleteButton onRemoveClick={this.onRemoveClick.bind(this,item.id)} key={index}/>;
}
renderTagOptions() {
@ -50,24 +45,23 @@ class TagSelector extends React.Component {
renderTagOption(item,index) {
return (
<div onClick={this.onTagSelected.bind(this,item.name)} className="tag-selector__tag-option" key={index}>
<div onClick={this.onTagSelected.bind(this,item.id)} className="tag-selector__tag-option" key={index}>
<span className="tag-selector__tag-option-square" style={{backgroundColor:item.color}}/>
<span className="tag-selector__tag-option-name" >{item.name}</span>
</div>
);
}
onRemoveClick(tag) {
onRemoveClick(tagId) {
if(this.props.onRemoveClick){
this.props.onRemoveClick(tag);
}
}
onTagSelected(tag) {
if(this.props.onTagSelected){
this.props.onTagSelected(tag);
this.props.onRemoveClick(tagId);
}
}
onTagSelected(tagId) {
if(this.props.onTagSelected){
this.props.onTagSelected(tagId);
}
}
}
export default TagSelector;

View File

@ -9,6 +9,7 @@
cursor: text;
background-color: white;
border: 1px solid $grey;
min-height: 38px;
&:focus {
outline: none;
@ -17,34 +18,6 @@
}
}
&__selected-tags {
border-radius: 3px;
background-color: white;
padding: 3px 1px;
}
&__selected-tag {
color: white;
display: inline-block;
border-radius: 3px;
margin-left: 5px;
padding: 3px;
font-size: 13px;
}
&__selected-tag {
cursor: default;
&-remove {
cursor: pointer;
margin-left: 10px;
&:hover {
color: $light-grey;
}
}
}
&__tag-options {
font-size: 13px;
color: $dark-grey;

View File

@ -0,0 +1,42 @@
import React from 'react';
import Icon from 'core-components/icon';
import classNames from 'classnames';
class Tag extends React.Component {
static propTypes = {
name: React.PropTypes.string,
color: React.PropTypes.string,
showDeleteButton: React.PropTypes.bool,
onRemoveClick: React.PropTypes.func,
size: React.PropTypes.oneOf(['small','medium'])
};
render() {
return (
<div className={this.getClass()} style={{backgroundColor:this.props.color}} onClick={event => event.stopPropagation()} >
<span className="tag__name">{this.props.name}</span>
{this.props.showDeleteButton ? this.renderRemoveButton() : null}
</div>
);
}
renderRemoveButton() {
return (
<span onClick={this.props.onRemoveClick} className="tag__remove" >
<Icon name="times-circle" size="small"/>
</span>
);
}
getClass() {
let classes = {
'tag': true,
'tag_small': this.props.size === 'small',
'tag_medium': this.props.size === 'medium'
};
return classNames(classes);
}
}
export default Tag;

View File

@ -0,0 +1,24 @@
@import '../scss/vars';
.tag{
color: white;
display: inline-block;
border-radius: 3px;
margin-left: 5px;
padding: 3px;
font-size: 13px;
cursor: default;
&__remove {
cursor: pointer;
margin-left: 10px;
&:hover {
color: $light-grey;
}
}
&_small {
font-size: 11px;
}
}

View File

@ -62,6 +62,8 @@ class SessionStore {
this.setItem('allow-attachments', configs['allow-attachments']);
this.setItem('maintenance-mode', configs['maintenance-mode']);
this.setItem('max-size', configs['max-size']);
this.setItem('tags', configs['tags']);
}
getConfigs() {
@ -78,6 +80,7 @@ class SessionStore {
'allow-attachments': (this.getItem('allow-attachments') * 1),
'maintenance-mode': (this.getItem('maintenance-mode') * 1),
'max-size': this.getItem('max-size'),
'tags': this.getItem('tags')
};
}