Skip to content

Commit

Permalink
Refactor Content Tags Modal (#4970)
Browse files Browse the repository at this point in the history
Co-authored-by: Nilesh <[email protected]>
  • Loading branch information
Tishasoumya-02 and nileshgulia1 authored Sep 19, 2023
1 parent 27bd755 commit f2df63e
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 130 deletions.
1 change: 1 addition & 0 deletions news/4971.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Refactor ContentsTagsModal -@Tishasoumya-02
213 changes: 83 additions & 130 deletions src/components/manage/Contents/ContentsTagsModal.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
/**
* Contents tags modal.
* @module components/manage/Contents/ContentsTagsModal
*/

import React, { Component } from 'react';
import React, { useCallback, useEffect, useMemo } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { useDispatch, useSelector } from 'react-redux';
import { map } from 'lodash';
import { defineMessages, injectIntl } from 'react-intl';
import { defineMessages, useIntl } from 'react-intl';

import { usePrevious } from '@plone/volto/helpers';
import { updateContent } from '@plone/volto/actions';
import { ModalForm } from '@plone/volto/components';

Expand All @@ -32,133 +27,91 @@ const messages = defineMessages({
},
});

/**
* ContentsTagsModal class.
* @class ContentsTagsModal
* @extends Component
*/
class ContentsTagsModal extends Component {
/**
* Property types.
* @property {Object} propTypes Property types.
* @static
*/
static propTypes = {
updateContent: PropTypes.func.isRequired,
items: PropTypes.arrayOf(
PropTypes.shape({
subjects: PropTypes.arrayOf(PropTypes.string),
url: PropTypes.string,
}),
).isRequired,
request: PropTypes.shape({
loading: PropTypes.bool,
loaded: PropTypes.bool,
}).isRequired,
open: PropTypes.bool.isRequired,
onOk: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
};

/**
* Constructor
* @method constructor
* @param {Object} props Component properties
* @constructs ContentsUploadModal
*/
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
}
const ContentsTagsModal = (props) => {
const { items, open, onCancel, onOk } = props;
const intl = useIntl();
const dispatch = useDispatch();
const request = useSelector((state) => state.content.update);
const prevrequestloading = usePrevious(request.loading);

/**
* Component will receive props
* @method componentWillReceiveProps
* @param {Object} nextProps Next properties
* @returns {undefined}
*/
UNSAFE_componentWillReceiveProps(nextProps) {
if (this.props.request.loading && nextProps.request.loaded) {
this.props.onOk();
useEffect(() => {
if (prevrequestloading && request.loaded) {
onOk();
}
}
}, [onOk, prevrequestloading, request.loaded]);

/**
* Submit handler
* @method onSubmit
* @param {Object} data Form data
* @returns {undefined}
*/
onSubmit({ tags_to_add = [], tags_to_remove = [] }) {
this.props.updateContent(
map(this.props.items, (item) => item.url),
map(this.props.items, (item) => ({
subjects: [
...new Set(
(item.subjects ?? [])
.filter((s) => !tags_to_remove.includes(s))
.concat(tags_to_add),
),
],
})),
);
}
const onSubmit = useCallback(
({ tags_to_add = [], tags_to_remove = [] }) => {
dispatch(
updateContent(
map(items, (item) => item.url),
map(items, (item) => ({
subjects: [
...new Set(
(item.subjects ?? [])
.filter((s) => !tags_to_remove.includes(s))
.concat(tags_to_add),
),
],
})),
),
);
},
[dispatch, items],
);

/**
* Render method.
* @method render
* @returns {string} Markup for the component.
*/
render() {
const currentSetTags = [
...new Set(this.props.items.map((item) => item.subjects).flat()),
];
const currentSetTags = useMemo(
() => [...new Set(items.map((item) => item.subjects).flat())],
[items],
);

return (
this.props.open && (
<ModalForm
open={this.props.open}
onSubmit={this.onSubmit}
onCancel={this.props.onCancel}
title={this.props.intl.formatMessage(messages.tags)}
schema={{
fieldsets: [
{
id: 'default',
title: this.props.intl.formatMessage(messages.default),
fields: ['tags_to_remove', 'tags_to_add'],
},
],
properties: {
tags_to_remove: {
type: 'array',
widget: 'array',
title: this.props.intl.formatMessage(messages.tagsToRemove),
choices: currentSetTags.map((tag) => [tag, tag]),
},
tags_to_add: {
type: 'array',
widget: 'token',
title: this.props.intl.formatMessage(messages.tagsToAdd),
items: {
vocabulary: { '@id': 'plone.app.vocabularies.Keywords' },
},
return (
open && (
<ModalForm
open={open}
onSubmit={onSubmit}
onCancel={onCancel}
title={intl.formatMessage(messages.tags)}
schema={{
fieldsets: [
{
id: 'default',
title: intl.formatMessage(messages.default),
fields: ['tags_to_remove', 'tags_to_add'],
},
],
properties: {
tags_to_remove: {
type: 'array',
widget: 'array',
title: intl.formatMessage(messages.tagsToRemove),
choices: currentSetTags.map((tag) => [tag, tag]),
},
tags_to_add: {
type: 'array',
widget: 'token',
title: intl.formatMessage(messages.tagsToAdd),
items: {
vocabulary: { '@id': 'plone.app.vocabularies.Keywords' },
},
},
required: [],
}}
/>
)
);
}
}
},
required: [],
}}
/>
)
);
};

export default compose(
injectIntl,
connect(
(state) => ({
request: state.content.update,
ContentsTagsModal.propTypes = {
items: PropTypes.arrayOf(
PropTypes.shape({
subjects: PropTypes.arrayOf(PropTypes.string),
url: PropTypes.string,
}),
{ updateContent },
),
)(ContentsTagsModal);
).isRequired,
open: PropTypes.bool.isRequired,
onOk: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
};
export default ContentsTagsModal;
68 changes: 68 additions & 0 deletions src/components/manage/Contents/ContentsTagsModal.stories.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { injectIntl } from 'react-intl';
import React from 'react';
import ContentsTagsModalComponent from './ContentsTagsModal';
import { RealStoreWrapper as Wrapper } from '@plone/volto/storybook';
import { bool } from 'prop-types';

const IntlContentTagsModalComponent = injectIntl(ContentsTagsModalComponent);

function StoryComponent(args) {
return (
<Wrapper
customStore={{
content: {
update: {
loading: false,
loaded: true,
},
},
intl: {
locale: 'en',
messages: {},
},
}}
>
<div id="toolbar" style={{ display: 'none' }} />
<IntlContentTagsModalComponent
{...args}
onOk={() => {}}
onCancel={() => {}}
items={[
{
...args,
url: '/blog',
},
]}
/>
</Wrapper>
);
}

export const ContentTagsModal = StoryComponent.bind({});

ContentTagsModal.args = {
subjects: ['plone 6 ', 'plone 5', 'plone'],
open: true,
};

export default {
title: 'Public components/Contents/Content Tags Modal',
component: ContentTagsModal,
decorators: [
(Story) => (
<div className="ui segment form attached" style={{ width: '400px' }}>
<Story />
</div>
),
],
argTypes: {
subjects: {
context: 'json',
description: 'Added tags',
},
open: {
context: bool,
description: 'open/close modal',
},
},
};

0 comments on commit f2df63e

Please sign in to comment.