Add edit buttons for fields in ticket viewer (#835)

* Fix style color in autocomplete component and dropdown in ticket search and ticket viewer.

* Change style of ticket status edit in ticket viewer.

* Redirect to ticket search when author name was clicked in ticket viewer

* Add i18n ASSIGNED_TO_ME.

* Add content on selected in dropdown component.

* Add styles in edit tags in ticket viewers

* Add edit owner and delete i18n ASSIGNED_TO_ME.

* Redirect to ticket search when owner name was clicked in ticket viewer

* Add style in edit department in ticket viewer.

* Add nav links in owner and author in ticket viewer.
This commit is contained in:
LautaroCesso 2020-07-30 22:30:48 -03:00 committed by GitHub
parent 1ecf619892
commit 938e25b2fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 339 additions and 111 deletions

View File

@ -63,7 +63,7 @@ class TicketQueryFilters extends React.Component {
</div> </div>
<div className="ticket-query-filters__row__filter"> <div className="ticket-query-filters__row__filter">
<span>{i18n('STATUS')}</span> <span>{i18n('STATUS')}</span>
<FormField name="closed" field="select" fieldProps={{items: this.getStatusItems()}} /> <FormField name="closed" field="select" fieldProps={{items: this.getStatusItems(), className: 'ticket-query-filters__group__container__status-drop-down'}} />
</div> </div>
</div> </div>
<div className="ticket-query-filters__row"> <div className="ticket-query-filters__row">

View File

@ -17,6 +17,7 @@
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
&__button { &__button {
margin: 0 10px; margin: 0 10px;
} }
@ -52,6 +53,14 @@
flex-direction: column; flex-direction: column;
align-items: start; align-items: start;
margin-bottom: 30px; margin-bottom: 30px;
&__status-drop-down > .drop-down__current-item {
background-color: $very-light-grey;
&:focus {
background-color: $medium-grey;
}
}
} }
} }

View File

@ -9,6 +9,7 @@ import API from 'lib-app/api-call';
import SessionStore from 'lib-app/session-store'; import SessionStore from 'lib-app/session-store';
import MentionsParser from 'lib-app/mentions-parser'; import MentionsParser from 'lib-app/mentions-parser';
import history from 'lib-app/history'; import history from 'lib-app/history';
import searchTicketsUtils from 'lib-app/search-tickets-utils';
import TicketEvent from 'app-components/ticket-event'; import TicketEvent from 'app-components/ticket-event';
import AreYouSure from 'app-components/are-you-sure'; import AreYouSure from 'app-components/are-you-sure';
@ -66,41 +67,58 @@ class TicketViewer extends React.Component {
newTitle: this.props.ticket.title, newTitle: this.props.ticket.title,
editTitleError: false, editTitleError: false,
editTitleLoading: false, editTitleLoading: false,
editStatus: false,
editTags: false,
editOwner: false,
editDepartment: false,
}; };
componentDidMount() { componentDidMount() {
if(!this.props.staffMembersLoaded && this.props.userStaff) { const {
this.props.dispatch(AdminDataActions.retrieveStaffMembers()); staffMembersLoaded,
userStaff,
dispatch
} = this.props;
if(!staffMembersLoaded && userStaff) {
dispatch(AdminDataActions.retrieveStaffMembers());
} }
} }
render() { render() {
const ticket = this.props.ticket; const {
ticket,
userStaff,
userId,
editable,
allowAttachments,
assignmentAllowed
} = this.props;
return ( return (
<div className="ticket-viewer"> <div className="ticket-viewer">
{this.state.editTitle ? this.renderEditableTitle() : this.renderTitleHeader()} {this.state.editTitle ? this.renderEditableTitle() : this.renderTitleHeader()}
{this.props.editable ? this.renderEditableHeaders() : this.renderHeaders()} {editable ? this.renderEditableHeaders() : this.renderHeaders()}
<div className="ticket-viewer__content"> <div className="ticket-viewer__content">
<TicketEvent <TicketEvent
loading={this.state.loading} loading={this.state.loading}
type="COMMENT" type="COMMENT"
author={ticket.author} author={ticket.author}
content={this.props.userStaff ? MentionsParser.parse(ticket.content) : ticket.content} content={userStaff ? MentionsParser.parse(ticket.content) : ticket.content}
userStaff={this.props.userStaff} userStaff={userStaff}
userId={this.props.userId} userId={userId}
date={ticket.date} date={ticket.date}
onEdit={this.onEdit.bind(this,0)} onEdit={this.onEdit.bind(this,0)}
edited={ticket.edited} edited={ticket.edited}
file={ticket.file} file={ticket.file}
edit={this.state.edit && this.state.editId == 0} edit={this.state.edit && this.state.editId == 0}
onToggleEdit={this.onToggleEdit.bind(this, 0)} onToggleEdit={this.onToggleEdit.bind(this, 0)}
allowAttachments={this.props.allowAttachments} /> allowAttachments={allowAttachments} />
</div> </div>
<div className="ticket-viewer__comments"> <div className="ticket-viewer__comments">
{ticket.events && ticket.events.map(this.renderTicketEvent.bind(this))} {ticket.events && ticket.events.map(this.renderTicketEvent.bind(this))}
</div> </div>
{(!this.props.ticket.closed && (this.props.editable || !this.props.assignmentAllowed)) ? this.renderResponseField() : (this.showDeleteButton())? <Button size="medium" onClick={this.onDeleteTicketClick.bind(this)}>{i18n('DELETE_TICKET')}</Button> : null} {(!ticket.closed && (editable || !assignmentAllowed)) ? this.renderResponseField() : (this.showDeleteButton())? <Button size="medium" onClick={this.onDeleteTicketClick.bind(this)}>{i18n('DELETE_TICKET')}</Button> : null}
</div> </div>
); );
} }
@ -114,7 +132,7 @@ class TicketViewer extends React.Component {
<span className="ticket-viewer__number">#{ticketNumber}</span> <span className="ticket-viewer__number">#{ticketNumber}</span>
<span className="ticket-viewer__title">{title}</span> <span className="ticket-viewer__title">{title}</span>
<span className="ticket-viewer__flag"> <span className="ticket-viewer__flag">
<Icon name={(language === 'en') ? 'us' : language}/> <Icon name={(language === 'en') ? 'us' : language} />
</span> </span>
{((author.id == userId && author.staff == userStaff) || userStaff) ? this.renderEditTitleOption() : null} {((author.id == userId && author.staff == userStaff) || userStaff) ? this.renderEditTitleOption() : null}
{editedTitle ? this.renderEditedTitleText() : null } {editedTitle ? this.renderEditedTitleText() : null }
@ -122,20 +140,6 @@ class TicketViewer extends React.Component {
) )
} }
renderEditedTitleText(){
return(
<div className="ticket-viewer__edited-title-text"> {i18n('TITLE_EDITED')} </div>
)
}
renderEditTitleOption() {
return(
<span className="ticket-viewer__edit-title-icon">
<Icon name="pencil" onClick={() => this.setState({editTitle: true})} />
</span>
)
}
renderEditableTitle(){ renderEditableTitle(){
return( return(
<div className="ticket-viewer__header"> <div className="ticket-viewer__header">
@ -160,59 +164,114 @@ class TicketViewer extends React.Component {
} }
renderEditableHeaders() { renderEditableHeaders() {
const ticket = this.props.ticket; const { userStaff, ticket } = this.props;
const departments = this.getDepartmentsForTransfer(); const filtersOnlyWithAuthor = {
authors: [
{
id: ticket.author.id*1,
isStaff: ticket.author.staff*1
}
]
};
return ( return (
<div className="ticket-viewer__headers"> <div className="ticket-viewer__headers">
<div className="ticket-viewer__info"> <div className="ticket-viewer__info">
<div className="ticket-viewer__info-container-editable"> <div className="ticket-viewer__info-container-editable">
<div className="ticket-viewer__info-header">{i18n('DEPARTMENT')}</div> <div className="ticket-viewer__info-container-editable__column">
<div className="ticket-viewer__info-value"> <div className="ticket-viewer__info-header">{i18n('DEPARTMENT')}</div>
<DepartmentDropdown <div className="ticket-viewer__info-value">
className="ticket-viewer__editable-dropdown" {
departments={departments} this.state.editDepartment ?
selectedIndex={_.findIndex(departments, {id: this.props.ticket.department.id})} this.renderEditDepartment() :
onChange={this.onDepartmentDropdownChanged.bind(this)} /> ticket.department.name
}
</div>
</div> </div>
{userStaff ? this.renderEditOption("Department") : null}
</div> </div>
<div className="ticket-viewer__info-container-editable"> <div className="ticket-viewer__info-container-editable">
<div className="ticket-viewer__info-header">{i18n('TAGS')}</div> <div className="ticket-viewer__info-container-editable__column">
<div className="ticket-viewer__info-value"> <div className="ticket-viewer__info-header">{i18n('TAGS')}</div>
<TagSelector <div className="ticket-viewer__info-value">
items={this.props.tags} {
values={this.props.ticket.tags} this.state.editTags ?
onRemoveClick={this.removeTag.bind(this)} this.renderEditTags() :
onTagSelected={this.addTag.bind(this)} this.renderTags()
loading={this.state.tagSelectorLoading}/> }
</div>
</div> </div>
{userStaff ? this.renderEditOption("Tags") : null}
</div> </div>
<div className="ticket-viewer__info-container-editable"> <div className="ticket-viewer__info-container-editable">
<div className="ticket-viewer__info-header">{i18n('OWNER')}</div> <div className="ticket-viewer__info-container-editable__column">
<div className="ticket-viewer__info-value"> <div className="ticket-viewer__info-header">{i18n('OWNER')}</div>
{this.renderAssignStaffList()} <div className="ticket-viewer__info-value">
{this.renderOwnerNode()}
</div>
</div> </div>
{userStaff ? this.renderEditOption("Owner") : null}
</div> </div>
</div> </div>
<div className="ticket-viewer__info"> <div className="ticket-viewer__info">
<div className="ticket-viewer__info-container-editable">
<div className="ticket-viewer__info-header">{i18n('AUTHOR')}</div>
<div className="ticket-viewer__info-value">{ticket.author.name}</div>
</div>
<div className="ticket-viewer__info-container-editable"> <div className="ticket-viewer__info-container-editable">
<div className="ticket-viewer__info-header">{i18n('STATUS')}</div> <div className="ticket-viewer__info-container-editable__column">
<div className="ticket-viewer__info-header">{i18n('AUTHOR')}</div>
<div className="ticket-viewer__info-value"> <div className="ticket-viewer__info-value">
{ticket.closed ? <a className="ticket-viewer__info-author-name" href={this.searchTickets(filtersOnlyWithAuthor)}>
<Button type='secondary' size="extra-small" onClick={this.onReopenClick.bind(this)}> {ticket.author.name}
{i18n('RE_OPEN')} </a>
</Button> : i18n('OPENED')} </div>
</div> </div>
</div> </div>
<div className="ticket-viewer__info-container-editable">
<div className="ticket-viewer__info-container-editable__column">
<div className="ticket-viewer__info-header">{i18n('STATUS')}</div>
<div className="ticket-viewer__info-value">
{this.state.editStatus ? this.renderEditStatus() : (ticket.closed ? i18n('CLOSED') : i18n('OPENED'))}
</div>
</div>
{userStaff ? this.renderEditOption("Status") : null}
</div>
</div> </div>
</div> </div>
); );
} }
renderEditTags() {
const {
tags,
ticket
} = this.props;
return (
<div className="ticket-viewer__edit-tags">
<TagSelector
items={tags}
values={ticket.tags}
onRemoveClick={this.removeTag.bind(this)}
onTagSelected={this.addTag.bind(this)}
loading={this.state.tagSelectorLoading} />
{this.renderCancelButton("Tags")}
</div>
);
}
renderEditStatus() {
return (
<div className="ticket-viewer__edit-status__buttons">
{this.renderCancelButton("Status")}
{this.props.ticket.closed ?
<Button type='secondary' size="medium" onClick={this.onReopenClick.bind(this)}>
{i18n('RE_OPEN')}
</Button> :
<Button type='secondary' size="medium" onClick={this.onCloseTicketClick.bind(this)}>
{i18n('CLOSE')}
</Button>}
</div>
);
}
renderHeaders() { renderHeaders() {
const ticket = this.props.ticket; const ticket = this.props.ticket;
@ -229,10 +288,9 @@ class TicketViewer extends React.Component {
</div> </div>
<div className="ticket-viewer__info-container"> <div className="ticket-viewer__info-container">
<div className="ticket-viewer__info-header">{i18n('TAGS')}</div> <div className="ticket-viewer__info-header">{i18n('TAGS')}</div>
<div className="ticket-viewer__info-value">{ticket.tags.length ? ticket.tags.map((tagName,index) => { <div className="ticket-viewer__info-value">
let tag = _.find(this.props.tags, {name:tagName}); {this.renderTags()}
return <Tag name={tag && tag.name} color={tag && tag.color} key={index} /> </div>
}) : i18n('NONE')}</div>
</div> </div>
</div> </div>
<div className="ticket-viewer__info"> <div className="ticket-viewer__info">
@ -245,7 +303,7 @@ class TicketViewer extends React.Component {
<div className="ticket-viewer__info-container"> <div className="ticket-viewer__info-container">
<div className="ticket-viewer__info-header">{i18n('STATUS')}</div> <div className="ticket-viewer__info-header">{i18n('STATUS')}</div>
<div className="ticket-viewer__info-value"> <div className="ticket-viewer__info-value">
{i18n((this.props.ticket.closed) ? 'CLOSED' : 'OPENED')} {i18n((ticket.closed) ? 'CLOSED' : 'OPENED')}
</div> </div>
</div> </div>
</div> </div>
@ -253,53 +311,137 @@ class TicketViewer extends React.Component {
); );
} }
renderOwnerNode() { renderTags() {
let ownerNode = null; const {
ticket,
tags
} = this.props;
const TAGS = (
ticket.tags.length ?
ticket.tags.map((tagName, index) => {
const tag = _.find(tags, {name: tagName});
return <Tag name={tag && tag.name} color={tag && tag.color} key={index} />
}) :
i18n('NONE')
);
if (this.props.assignmentAllowed) { return TAGS;
ownerNode = this.renderAssignStaffList();
} else {
ownerNode = (this.props.ticket.owner) ? this.props.ticket.owner.name : i18n('NONE')
}
return ownerNode;
} }
renderAssignStaffList() { renderOwnerNode() {
const {
assignmentAllowed,
ticket
} = this.props;
const filtersOnlyWithOwner = ticket.owner && {owners: [ticket.owner.id*1]};
let ownerNode = null;
if(assignmentAllowed && ticket.owner) {
ownerNode = (
<a className="ticket-viewer__info-owner-name" href={this.searchTickets(filtersOnlyWithOwner)}>
{ticket.owner.name}
</a>
);
} else {
ownerNode = (
<span className="ticket-viewer__info-owner-name">
{(ticket.owner) ? ticket.owner.name : i18n('NONE')}
</span>
);
}
return (assignmentAllowed && this.state.editOwner) ? this.renderEditOwner() : ownerNode;
}
renderEditOwner() {
const items = this.getStaffAssignmentItems(); const items = this.getStaffAssignmentItems();
const ownerId = this.props.ticket.owner && this.props.ticket.owner.id*1; const { ticket } = this.props;
const ownerId = ticket.owner && ticket.owner.id*1;
let selectedIndex = _.findIndex(items, {id: ownerId}); let selectedIndex = _.findIndex(items, {id: ownerId});
selectedIndex = (selectedIndex !== -1) ? selectedIndex : 0; selectedIndex = (selectedIndex !== -1) ? selectedIndex : 0;
return ( return (
<DropDown <div className="ticket-viewer__edit-owner">
className="ticket-viewer__editable-dropdown" items={items} <DropDown
selectedIndex={selectedIndex} className="ticket-viewer__editable-dropdown" items={items}
onChange={this.onAssignmentChange.bind(this)} selectedIndex={selectedIndex}
/> onChange={this.onAssignmentChange.bind(this)} />
{this.renderCancelButton("Owner")}
</div>
); );
} }
renderEditDepartment() {
const { ticket } = this.props;
const departments = this.getDepartmentsForTransfer();
return (
<div className="ticket-viewer__edit-owner">
<DepartmentDropdown
className="ticket-viewer__editable-dropdown"
departments={departments}
selectedIndex={_.findIndex(departments, {id: ticket.department.id})}
onChange={this.onDepartmentDropdownChanged.bind(this)} />
{this.renderCancelButton("Department")}
</div>
);
}
renderEditTitleOption() {
return(
<span className="ticket-viewer__edit-title-icon">
<Icon name="pencil" onClick={() => this.setState({editTitle: true})} />
</span>
)
}
renderEditOption(option) {
return(
<span className="ticket-viewer__edit-icon">
<Icon name="pencil" onClick={() => this.setState({["edit"+option]: true})} />
</span>
);
}
renderEditedTitleText(){
return(
<div className="ticket-viewer__edited-title-text"> {i18n('TITLE_EDITED')} </div>
)
}
renderCancelButton(option) {
return <Button type='link' size="medium" onClick={() => this.setState({["edit"+option]: false})}>{i18n('CANCEL')}</Button>
}
renderTicketEvent(options, index) { renderTicketEvent(options, index) {
if (this.props.userStaff && typeof options.content === 'string') { const {
userStaff,
ticket,
userId,
allowAttachments
} = this.props;
if(userStaff && typeof options.content === 'string') {
options.content = MentionsParser.parse(options.content); options.content = MentionsParser.parse(options.content);
} }
return ( return (
<TicketEvent <TicketEvent
{...options} {...options}
author={(!_.isEmpty(options.author)) ? options.author : this.props.ticket.author} author={(!_.isEmpty(options.author)) ? options.author : ticket.author}
userStaff={this.props.userStaff} userStaff={userStaff}
userId={this.props.userId} userId={userId}
onEdit={this.onEdit.bind(this, options.id)} onEdit={this.onEdit.bind(this, options.id)}
edit={this.state.edit && this.state.editId == options.id} edit={this.state.edit && this.state.editId == options.id}
onToggleEdit={this.onToggleEdit.bind(this, options.id)} onToggleEdit={this.onToggleEdit.bind(this, options.id)}
key={index} key={index}
allowAttachments={this.props.allowAttachments} allowAttachments={allowAttachments} />
/>
); );
} }
renderResponseField() { renderResponseField() {
const { allowAttachments } = this.props;
return ( return (
<div className="ticket-viewer__response"> <div className="ticket-viewer__response">
<Form {...this.getCommentFormProps()}> <Form {...this.getCommentFormProps()}>
@ -311,12 +453,11 @@ class TicketViewer extends React.Component {
</div> </div>
</div> </div>
<div className="ticket-viewer__response-field row"> <div className="ticket-viewer__response-field row">
<FormField name="content" validation="TEXT_AREA" required field="textarea" fieldProps={{allowImages: this.props.allowAttachments}}/> <FormField name="content" validation="TEXT_AREA" required field="textarea" fieldProps={{allowImages: allowAttachments}} />
{(this.props.allowAttachments) ? <FormField name="file" field="file"/> : null} {allowAttachments ? <FormField name="file" field="file" /> : null}
<div className="ticket-viewer__response-buttons"> <div className="ticket-viewer__response-buttons">
<SubmitButton type="secondary">{i18n('RESPOND_TICKET')}</SubmitButton> <SubmitButton type="secondary">{i18n('RESPOND_TICKET')}</SubmitButton>
<div> <div>
<Button size="medium" onClick={this.onCloseTicketClick.bind(this)}>{i18n('CLOSE_TICKET')}</Button>
{(this.showDeleteButton())? <Button className="ticket-viewer__delete-button" size="medium" onClick={this.onDeleteTicketClick.bind(this)}>{i18n('DELETE_TICKET')}</Button> : null} {(this.showDeleteButton())? <Button className="ticket-viewer__delete-button" size="medium" onClick={this.onDeleteTicketClick.bind(this)}>{i18n('DELETE_TICKET')}</Button> : null}
</div> </div>
</div> </div>
@ -330,7 +471,7 @@ class TicketViewer extends React.Component {
renderCustomResponses() { renderCustomResponses() {
let customResponsesNode = null; let customResponsesNode = null;
if (this.props.customResponses && this.props.editable) { if(this.props.customResponses && this.props.editable) {
let customResponses = this.props.customResponses.map((customResponse) => { let customResponses = this.props.customResponses.map((customResponse) => {
return { return {
content: customResponse.name content: customResponse.name
@ -343,7 +484,7 @@ class TicketViewer extends React.Component {
customResponsesNode = ( customResponsesNode = (
<div className="ticket-viewer__response-custom"> <div className="ticket-viewer__response-custom">
<DropDown items={customResponses} size="medium" onChange={this.onCustomResponsesChanged.bind(this)}/> <DropDown items={customResponses} size="medium" onChange={this.onCustomResponsesChanged.bind(this)} />
</div> </div>
); );
} }
@ -352,10 +493,10 @@ class TicketViewer extends React.Component {
} }
renderPrivate() { renderPrivate() {
if (this.props.userStaff) { if(this.props.userStaff) {
return ( return (
<div className="ticket-viewer__response-private"> <div className="ticket-viewer__response-private">
<FormField label={i18n('PRIVATE')} name="private" field="checkbox"/> <FormField label={i18n('PRIVATE')} name="private" field="checkbox" />
<InfoTooltip className="ticket-viewer__response-private-info" text={i18n('PRIVATE_RESPONSE_DESCRIPTION')} /> <InfoTooltip className="ticket-viewer__response-private-info" text={i18n('PRIVATE_RESPONSE_DESCRIPTION')} />
</div> </div>
); );
@ -370,6 +511,13 @@ class TicketViewer extends React.Component {
); );
} }
searchTickets(filters) {
const SEARCH_TICKETS_PATH = '/admin/panel/tickets/search-tickets';
const urlQuery = filters && searchTicketsUtils.getFiltersForURL({filters});
return urlQuery && `${SEARCH_TICKETS_PATH}${urlQuery}`;
}
getCommentFormProps() { getCommentFormProps() {
return { return {
onSubmit: this.onSubmit.bind(this), onSubmit: this.onSubmit.bind(this),
@ -424,10 +572,18 @@ class TicketViewer extends React.Component {
} }
onReopenClick() { onReopenClick() {
this.setState({
editStatus: false
});
AreYouSure.openModal(null, this.reopenTicket.bind(this)); AreYouSure.openModal(null, this.reopenTicket.bind(this));
} }
onCloseTicketClick(event) { onCloseTicketClick(event) {
this.setState({
editStatus: false
});
event.preventDefault(); event.preventDefault();
AreYouSure.openModal(null, this.closeTicket.bind(this)); AreYouSure.openModal(null, this.closeTicket.bind(this));
} }
@ -646,47 +802,77 @@ class TicketViewer extends React.Component {
} }
onTicketModification() { onTicketModification() {
if (this.props.onChange) { const { onChange } = this.props;
this.props.onChange(); if(onChange) {
onChange();
} }
} }
getStaffAssignmentItems() { getStaffAssignmentItems() {
const {staffMembers, userDepartments, userId, ticket} = this.props; const {
userDepartments,
userId,
ticket
} = this.props;
const ticketDepartmentId = ticket.department.id; const ticketDepartmentId = ticket.department.id;
const FIRST_ITEM = 0;
let staffAssignmentItems = [ let staffAssignmentItems = [
{content: 'None', id: 0} {content: i18n('NONE'), contentOnSelected: i18n('NONE'), id: 0}
]; ];
if(_.some(userDepartments, {id: ticketDepartmentId})) { if(_.some(userDepartments, {id: ticketDepartmentId})) {
staffAssignmentItems.push({content: i18n('ASSIGN_TO_ME'), id: userId}); staffAssignmentItems.push({
content: i18n('ASSIGN_TO_ME'),
contentOnSelected: this.getStaffList({onlyMe: true})[FIRST_ITEM].name,
id: userId
});
} }
staffAssignmentItems = staffAssignmentItems.concat( staffAssignmentItems = staffAssignmentItems.concat(
_.map( _.map(
_.filter(staffMembers, ({id, departments}) => { this.getStaffList({onlyMe: false}),
return (id != userId) && _.some(departments, {id: ticketDepartmentId}); ({id, name}) => ({content: name, contentOnSelected: name, id: id*1})
}),
({id, name}) => ({content: name, id: id*1})
) )
); );
return staffAssignmentItems; return staffAssignmentItems;
} }
getStaffList(onlyMeObject) {
const {
userId,
staffMembers,
ticket
} = this.props;
return _.filter(staffMembers, ({id, departments}) => {
const idComparer = onlyMeObject.onlyMe ? (id == userId) : (id != userId);
return idComparer && _.some(departments, {id: ticket.department.id});
})
}
getDepartmentsForTransfer() { getDepartmentsForTransfer() {
return this.props.ticket.author.staff ? SessionStore.getDepartments() : this.getPublicDepartments(); return this.props.ticket.author.staff ? SessionStore.getDepartments() : this.getPublicDepartments();
} }
showDeleteButton() { showDeleteButton() {
if(!this.props.ticket.owner) { const {
if(this.props.userLevel === 3) return true; ticket,
if(this.props.userId == this.props.ticket.author.id*1) { userLevel,
if((this.props.userStaff && this.props.ticket.author.staff) || (!this.props.userStaff && !this.props.ticket.author.staff)){ userId,
userStaff
} = this.props;
if(!ticket.owner) {
if(userLevel === 3) return true;
if(userId == ticket.author.id*1) {
if((userStaff && ticket.author.staff) || (!userStaff && !ticket.author.staff)){
return true; return true;
} }
} }
} }
return false; return false;
} }
} }

View File

@ -26,15 +26,34 @@
margin: 0 10px; margin: 0 10px;
} }
&__edit-title-icon { &__edit-icon {
color: #414A59;
right: 12px; right: 12px;
margin: 0 10px; margin: 0 10px;
color: $light-grey;
&:hover { &:hover {
cursor:pointer; cursor:pointer;
} }
} }
&__edit-title-icon {
color: $primary-blue;
right: 12px;
margin: 0 10px;
&:hover {
cursor:pointer;
}
}
&__edit-status__buttons {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-top: 10px;
}
&___input-edit-title { &___input-edit-title {
color: black; color: black;
align-items:center; align-items:center;
@ -87,10 +106,24 @@
&-container-editable { &-container-editable {
display: flex; display: flex;
flex-direction: column; flex-direction: row;
justify-content: space-around; justify-content: center;
align-items: center; align-items: flex-start;
min-width: 300px; min-width: 300px;
&:hover {
.ticket-viewer__edit-icon {
color: $primary-blue;
}
}
&__column {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
min-width: 170px;
}
} }
&-header { &-header {
@ -100,7 +133,7 @@
&-value { &-value {
color: $secondary-blue; color: $secondary-blue;
padding-bottom: 10px; padding-bottom: 10px;
width: 100%;
} }
} }

View File

@ -7,14 +7,14 @@
&__drop-down { &__drop-down {
.drop-down__current-item { .drop-down__current-item {
cursor: text; cursor: text;
background-color: white; background-color: $very-light-grey;
border: 1px solid $grey; border: 1px solid $grey;
min-height: 38px; min-height: 38px;
&:focus-within { &:focus-within {
outline: none; outline: none;
border-color: $primary-blue; border-color: $primary-blue;
background-color: white; background-color: $very-light-grey;
} }
} }

View File

@ -89,7 +89,7 @@ class DropDown extends React.Component {
} }
renderCurrentItem() { renderCurrentItem() {
let item = this.props.items[this.getSelectedIndex()]; const item = this.props.items[this.getSelectedIndex()];
let iconNode = null; let iconNode = null;
if (item.icon) { if (item.icon) {
@ -98,7 +98,7 @@ class DropDown extends React.Component {
return ( return (
<div> <div>
{iconNode}{item.content} {iconNode}{item.contentOnSelected ? item.contentOnSelected : item.content}
</div> </div>
); );
} }