mirror of
https://github.com/opensupports/opensupports.git
synced 2025-07-27 15:54:23 +02:00
create custom tag admin editor
This commit is contained in:
parent
5bf8ff94bc
commit
d96e8b44b1
@ -0,0 +1,103 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import i18n from 'lib-app/i18n';
|
||||||
|
import API from 'lib-app/api-call';
|
||||||
|
|
||||||
|
import Button from 'core-components/button';
|
||||||
|
import Header from 'core-components/header';
|
||||||
|
import Form from 'core-components/form';
|
||||||
|
import FormField from 'core-components/form-field';
|
||||||
|
import SubmitButton from 'core-components/submit-button';
|
||||||
|
import ColorSelector from 'core-components/color-selector';
|
||||||
|
|
||||||
|
class AdminPanelCustomTagsModal extends React.Component {
|
||||||
|
static contextTypes = {
|
||||||
|
closeModal: React.PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
defaultValues: React.PropTypes.object,
|
||||||
|
onTagCreated: React.PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
form: this.props.defaultValues || {name: '', color: '#ff6900'},
|
||||||
|
loading: false
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Header title={'new tags'} description={i18n('Here you can add a topic that works as a category for articles.')} />
|
||||||
|
<Form
|
||||||
|
values={this.state.form}
|
||||||
|
onChange={this.onFormChange.bind(this)}
|
||||||
|
onSubmit={this.onSubmitTag.bind(this)}
|
||||||
|
errors={this.state.errors}
|
||||||
|
onValidateErrors={errors => this.setState({errors})}
|
||||||
|
loading={this.state.loading}>
|
||||||
|
<FormField name="name" label={i18n('NAME')} fieldProps={{size: 'large'}} required />
|
||||||
|
<FormField name="color" label={i18n('COLOR')} decorator={ColorSelector} />
|
||||||
|
|
||||||
|
<SubmitButton className="topic-edit-modal__save-button" type="secondary" size="small">
|
||||||
|
{i18n('SAVE')}
|
||||||
|
</SubmitButton>
|
||||||
|
<Button className="topic-edit-modal__discard-button" onClick={this.onDiscardClick.bind(this)} size="small">
|
||||||
|
{i18n('CANCEL')}
|
||||||
|
</Button>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onFormChange(form) {
|
||||||
|
this.setState({
|
||||||
|
form
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmitTag(form) {
|
||||||
|
this.setState({
|
||||||
|
loading: true
|
||||||
|
});
|
||||||
|
|
||||||
|
API.call({
|
||||||
|
path: '/ticket/create-tag',
|
||||||
|
data: {
|
||||||
|
name: form.name,
|
||||||
|
color: form.color,
|
||||||
|
}
|
||||||
|
}).then(() => {
|
||||||
|
this.context.closeModal();
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
errors: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(this.props.onTagCreated) {
|
||||||
|
this.props.onTagCreated();
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((result) => {
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
errors: {
|
||||||
|
'name': result.message
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onDiscardClick(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.context.closeModal();
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
errors: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelCustomTagsModal;
|
@ -1,76 +1,40 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import _ from 'lodash';
|
|
||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
|
|
||||||
|
import AdminPanelCustomTagsModal from 'app/admin/panel/tickets/admin-panel-custom-tags-modal';
|
||||||
|
|
||||||
import i18n from 'lib-app/i18n';
|
import i18n from 'lib-app/i18n';
|
||||||
import API from 'lib-app/api-call';
|
import API from 'lib-app/api-call';
|
||||||
import AdminDataActions from 'actions/admin-data-actions';
|
import ConfigActions from 'actions/config-actions';
|
||||||
|
|
||||||
import AreYouSure from 'app-components/are-you-sure';
|
import AreYouSure from 'app-components/are-you-sure';
|
||||||
import LanguageSelector from 'app-components/language-selector';
|
import ModalContainer from 'app-components/modal-container';
|
||||||
|
|
||||||
import Icon from 'core-components/icon';
|
import Icon from 'core-components/icon';
|
||||||
import Button from 'core-components/button';
|
import Button from 'core-components/button';
|
||||||
import Header from 'core-components/header';
|
import Header from 'core-components/header';
|
||||||
import Listing from 'core-components/listing';
|
import Tag from 'core-components/tag';
|
||||||
import Loading from 'core-components/loading';
|
|
||||||
import Form from 'core-components/form';
|
|
||||||
import FormField from 'core-components/form-field';
|
|
||||||
import SubmitButton from 'core-components/submit-button';
|
|
||||||
import TextEditor from 'core-components/text-editor';
|
|
||||||
import ModalContainer from 'app-components/modal-container';
|
|
||||||
import ColorSelector from 'core-components/color-selector';
|
|
||||||
class TagList extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
const list = this.props.tags.map((tag) => {
|
|
||||||
<h1>{tag.name}</h1>;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{list}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class AdminPanelCustomTags extends React.Component {
|
class AdminPanelCustomTags extends React.Component {
|
||||||
static defaultProps = {
|
static propTypes = {
|
||||||
items: [],
|
tags: React.PropTypes.arrayOf(
|
||||||
};
|
React.PropTypes.shape({
|
||||||
|
name: React.PropTypes.string,
|
||||||
state = {
|
color: React.PropTypes.string,
|
||||||
formClicked: false,
|
id: React.PropTypes.number
|
||||||
showForm: false,
|
})
|
||||||
formLoading: false,
|
),
|
||||||
selectedIndex: -1,
|
|
||||||
errors: {},
|
|
||||||
originalForm: {
|
|
||||||
title: '',
|
|
||||||
content: TextEditor.createEmpty(),
|
|
||||||
language: this.props.language
|
|
||||||
},
|
|
||||||
form: {
|
|
||||||
title: '',
|
|
||||||
content: TextEditor.createEmpty(),
|
|
||||||
language: this.props.language
|
|
||||||
},
|
|
||||||
tagList: {} //
|
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (!this.props.loaded) {
|
this.retrieveCustomTags();
|
||||||
this.retrieveCustomResponses();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="admin-panel-custom-tags">
|
<div className="admin-panel-custom-tags">
|
||||||
<Header title={i18n('CUSTOM_TAGS')} description={i18n('CUSTOM_TAGS_DESCRIPTION')} />
|
<Header title={i18n('CUSTOM_TAGS')} description={i18n('CUSTOM_TAGS_DESCRIPTION')} />
|
||||||
{(this.props.loaded) ? this.renderContent() : this.renderLoading()}
|
{this.renderContent()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -79,183 +43,46 @@ class AdminPanelCustomTags extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-md-3">
|
<div className="col-md-3">
|
||||||
<Button onClick={this.onCreateTag.bind(this)} type="secondary" ><Icon name="pencil"/>'NUEVO TAGi18n'</Button>
|
<Button onClick={this.openTagModal.bind(this)} type="secondary" ><Icon name="pencil"/>'NUEVO TAGi18n'</Button>
|
||||||
<TagList tags={this.state.tagList}/>
|
|
||||||
</div>
|
</div>
|
||||||
|
{this.props.tags.map((tag) => {
|
||||||
|
return(
|
||||||
|
<Tag color={tag.color} name={tag.name} onRemoveClick={this.onDeleteClick.bind(this, tag.id)} showDeleteButton />
|
||||||
|
)
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
onCreateTag() {
|
|
||||||
|
openTagModal() {
|
||||||
ModalContainer.openModal(
|
ModalContainer.openModal(
|
||||||
<div>
|
<AdminPanelCustomTagsModal onTagCreated={this.retrieveCustomTags.bind(this)}/>
|
||||||
<Header title={'new tags'} description={i18n('Here you can add a topic that works as a category for articles.')} />
|
|
||||||
<Form values={this.state.values} onChange={this.onFormChange.bind(this)} onSubmit={this.onSubmitTag.bind(this)} loading={this.state.loading}>
|
|
||||||
<FormField name="title" label={i18n('TITLE')} fieldProps={{size: 'large'}} validation="TITLE" required />
|
|
||||||
<FormField name="color" className="topic-edit-modal__color" label={i18n('COLOR')} decorator={ColorSelector} />
|
|
||||||
<FormField className="topic-edit-modal__private" label={i18n('PRIVATE')} name="private" field="checkbox"/>
|
|
||||||
|
|
||||||
<SubmitButton className="topic-edit-modal__save-button" type="secondary" size="small">
|
|
||||||
{i18n('SAVE')}
|
|
||||||
</SubmitButton>
|
|
||||||
<Button className="topic-edit-modal__discard-button" onClick={this.onDiscardClick.bind(this)} size="small">
|
|
||||||
{i18n('CANCEL')}
|
|
||||||
</Button>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
onSubmitTag() {
|
|
||||||
API.call({
|
|
||||||
path: '/ticket/add-tag',
|
|
||||||
data: {
|
|
||||||
name: form.title,
|
|
||||||
color: form.content,
|
|
||||||
}
|
|
||||||
}).then(() => {
|
|
||||||
this.context.closeModal();
|
|
||||||
this.updateTagList();
|
|
||||||
|
|
||||||
if(this.props.onChange) {
|
onDeleteClick(tagId, event) {
|
||||||
this.props.onChange();
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
this.setState({
|
|
||||||
loading: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
onFormChange(form) {
|
|
||||||
this.setState({
|
|
||||||
values: form
|
|
||||||
});
|
|
||||||
}
|
|
||||||
onDiscardClick(event) {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.context.closeModal();
|
AreYouSure.openModal(i18n('WILL_DELETE_CUSTOM_RESPONSE'), this.deleteCustomTag.bind(this, tagId));
|
||||||
}
|
|
||||||
renderLoading() {
|
|
||||||
return (
|
|
||||||
<div className="admin-panel-custom-responses__loading">
|
|
||||||
<Loading backgrounded size="large"/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderOptionalButtons() {
|
deleteCustomTag(tagId) {
|
||||||
return (
|
|
||||||
<div className="admin-panel-custom-responses__optional-buttons">
|
|
||||||
<div className="admin-panel-custom-responses__discard-button">
|
|
||||||
{this.isEdited() ? <Button onClick={this.onDiscardChangesClick.bind(this)}>{i18n('DISCARD_CHANGES')}</Button> : null}
|
|
||||||
</div>
|
|
||||||
<div className="admin-panel-custom-responses__delete-button">
|
|
||||||
<Button onClick={this.onDeleteClick.bind(this)}>{i18n('DELETE')}</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
onItemChange(index) {
|
|
||||||
if(this.isEdited()) {
|
|
||||||
AreYouSure.openModal(i18n('WILL_LOSE_CHANGES'), this.updateForm.bind(this, index));
|
|
||||||
} else {
|
|
||||||
this.updateForm(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit() {
|
|
||||||
this.setState({
|
|
||||||
loading: true
|
|
||||||
});
|
|
||||||
|
|
||||||
API.call({
|
API.call({
|
||||||
path: (this.props.addForm) ? '/article/add-topic' : '/article/edit-topic',
|
path: '/ticket/delete-tag',
|
||||||
data: {
|
data: {
|
||||||
topicId: this.props.topicId,
|
tagId,
|
||||||
name: this.state.values['title'],
|
|
||||||
icon: this.state.values['icon'],
|
|
||||||
iconColor: this.state.values['color'],
|
|
||||||
private: this.state.values['private']*1
|
|
||||||
}
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.context.closeModal();
|
this.retrieveCustomTags()
|
||||||
|
|
||||||
if(this.props.onChange) {
|
|
||||||
this.props.onChange();
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
this.setState({
|
|
||||||
loading: false
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onDiscardChangesClick(event) {
|
retrieveCustomTags() {
|
||||||
event.preventDefault();
|
this.props.dispatch(ConfigActions.updateData());
|
||||||
this.onItemChange(this.state.selectedIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
onDeleteClick(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
AreYouSure.openModal(i18n('WILL_DELETE_CUSTOM_RESPONSE'), this.deleteCustomResponse.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteCustomResponse() {
|
|
||||||
API.call({
|
|
||||||
path: '/ticket/delete-custom-response',
|
|
||||||
data: {
|
|
||||||
id: this.props.items[this.state.selectedIndex].id
|
|
||||||
}
|
|
||||||
}).then(() => {
|
|
||||||
this.retrieveCustomResponses();
|
|
||||||
this.onItemChange(-1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
updateTagList() {
|
|
||||||
API.call({
|
|
||||||
path: '/ticket/get-tags'
|
|
||||||
}).then(() => {
|
|
||||||
this.setState({
|
|
||||||
tagList: data
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateForm(index) {
|
|
||||||
let form = _.clone(this.state.form);
|
|
||||||
|
|
||||||
form.title = (this.props.items[index] && this.props.items[index].name) || '';
|
|
||||||
form.content = TextEditor.getEditorStateFromHTML((this.props.items[index] && this.props.items[index].content) || '');
|
|
||||||
form.language = (this.props.items[index] && this.props.items[index].language) || this.props.language;
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
formClicked: false,
|
|
||||||
showForm: true,
|
|
||||||
selectedIndex: index,
|
|
||||||
formLoading: false,
|
|
||||||
originalForm: form,
|
|
||||||
form: form,
|
|
||||||
errors: {}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
retrieveCustomResponses() {
|
|
||||||
this.props.dispatch(AdminDataActions.retrieveCustomResponses());
|
|
||||||
}
|
|
||||||
|
|
||||||
isEdited() {
|
|
||||||
return this.state.form.title && this.state.formClicked && (
|
|
||||||
this.state.form.title != this.state.originalForm.title ||
|
|
||||||
this.state.form.content != this.state.originalForm.content ||
|
|
||||||
this.state.form.language != this.state.originalForm.language
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect((store) => {
|
export default connect((store) => {
|
||||||
return {
|
return {
|
||||||
allowedLanguages: store.config.allowedLanguages,
|
tags: store.config['tags']
|
||||||
language: store.config.language,
|
|
||||||
loaded: store.adminData.customResponsesLoaded,
|
|
||||||
items: store.adminData.customResponses
|
|
||||||
};
|
};
|
||||||
})(AdminPanelCustomTags);
|
})(AdminPanelCustomTags);
|
||||||
|
@ -87,7 +87,7 @@ let DemoPage = React.createClass({
|
|||||||
{name: 'tag4', color: 'green'},
|
{name: 'tag4', color: 'green'},
|
||||||
{name: 'bug', color: '#eb144c'},
|
{name: 'bug', color: '#eb144c'},
|
||||||
]}
|
]}
|
||||||
values={['suggestion','bug']}
|
values={['suggestion','bug', 'tag4']}
|
||||||
onRemoveClick={(e) => console.log('deleted click', e)}
|
onRemoveClick={(e) => console.log('deleted click', e)}
|
||||||
onTagSelected={(e) => console.log('selected click', e)}
|
onTagSelected={(e) => console.log('selected click', e)}
|
||||||
/>
|
/>
|
||||||
|
@ -62,7 +62,7 @@ class SessionStore {
|
|||||||
this.setItem('allow-attachments', configs['allow-attachments']);
|
this.setItem('allow-attachments', configs['allow-attachments']);
|
||||||
this.setItem('maintenance-mode', configs['maintenance-mode']);
|
this.setItem('maintenance-mode', configs['maintenance-mode']);
|
||||||
this.setItem('max-size', configs['max-size']);
|
this.setItem('max-size', configs['max-size']);
|
||||||
this.setItem('tags', configs['tags']);
|
this.setItem('tags', JSON.stringify(configs['tags']));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ class SessionStore {
|
|||||||
'allow-attachments': (this.getItem('allow-attachments') * 1),
|
'allow-attachments': (this.getItem('allow-attachments') * 1),
|
||||||
'maintenance-mode': (this.getItem('maintenance-mode') * 1),
|
'maintenance-mode': (this.getItem('maintenance-mode') * 1),
|
||||||
'max-size': this.getItem('max-size'),
|
'max-size': this.getItem('max-size'),
|
||||||
'tags': this.getItem('tags')
|
'tags': JSON.parse(this.getItem('tags'))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user