Skip to content

Commit

Permalink
EZP-31345 Added language select when user edit sub items (#270)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasOsti authored Feb 24, 2020
1 parent ffbfe33 commit 4dda573
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 93 deletions.
1 change: 1 addition & 0 deletions Resources/public/scss/modules/_sub.items.list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@import 'sub-items-list/table.view.columns.toggler';
@import 'sub-items-list/table.view.item';
@import 'sub-items-list/table.view';
@import 'sub-items-list/language.selector';
@import 'sub-items-list/view.switcher.button';
@import 'sub-items-list/view.switcher';
@import 'sub-items-list/main';
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.c-language-selector {
.ez-instant-filter {
&__items {
margin-top: calculateRem(5px);
max-height: calc(100vh - #{calculateRem(220px)});
overflow: auto;

.form-check-label {
font-size: calculateRem(16px);
line-height: calculateRem(50px);
}
}
}
}
170 changes: 90 additions & 80 deletions Resources/translations/sub_items.en.xliff

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React, { useEffect, useState, useRef } from 'react';
import PropTypes from 'prop-types';

const FILTER_TIMEOUT = 200;

const InstantFilter = (props) => {
const _refInstantFilter = useRef(null);
const [filterQuery, setFilterQuery] = useState('');
const [itemsMap, setItemsMap] = useState([]);
let filterTimeout = null;

useEffect(() => {
const items = [..._refInstantFilter.current.querySelectorAll('.ez-instant-filter__item')];
const itemsMap = items.map((item) => ({
label: item.textContent.toLowerCase(),
element: item,
}));

setItemsMap(itemsMap);
}, [props.items]);

useEffect(() => {
const filterQueryLowerCase = filterQuery.toLowerCase();

filterTimeout = window.setTimeout(() => {
itemsMap.forEach((item) => {
const methodName = item.label.includes(filterQueryLowerCase) ? 'removeAttribute' : 'setAttribute';

item.element[methodName]('hidden', true);
});
}, FILTER_TIMEOUT);

return () => {
window.clearTimeout(filterTimeout);
};
}, [filterQuery]);

return (
<div className="ez-instant-filter" ref={_refInstantFilter}>
<div className="ez-instant-filter__input-wrapper">
<input
type="text"
className="ez-instant-filter__input form-control"
placeholder={Translator.trans(/*@Desc("Type to refine")*/ 'instant.filter.placeholder', {}, 'sub_items')}
value={filterQuery}
onChange={(event) => setFilterQuery(event.target.value)}
/>
</div>
<div className="ez-instant-filter__items">
{props.items.map((item) => {
const radioId = `item_${item.value}`;

return (
<div className="ez-instant-filter__item">
<div className="form-check">
<input
type="radio"
id={radioId}
name="items"
className="form-check-input"
value={item.value}
onChange={() => props.handleItemChange(item.value)}
/>
<label className="form-check-label" for={radioId}>
{item.label}
</label>
</div>
</div>
);
})}
</div>
</div>
);
};

InstantFilter.propTypes = {
items: PropTypes.array,
handleItemChange: PropTypes.func,
};

InstantFilter.defaultProps = {
items: [],
handleItemChange: () => {},
};

export default InstantFilter;
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';

import { createCssClassNames } from '../../../common/helpers/css.class.names';
import InstantFilter from '../sub-items-list/instant.filter.component';

const LanguageSelector = (props) => {
const className = createCssClassNames({
'ez-extra-actions': true,
'c-language-selector': true,
'ez-extra-actions--edit': true,
'ez-extra-actions--hidden': !props.isOpen,
});
const closeLanguageSelector = (event) => {
if (!event.target.closest('.c-table-view-item__btn') && !event.target.classList.contains('ez-instant-filter__input')) {
props.close();
}
};

useEffect(() => {
window.document.addEventListener('click', closeLanguageSelector, false);

return () => {
window.document.removeEventListener('click', closeLanguageSelector);
};
}, []);

return (
<div className={className}>
<div className="ez-extra-actions__header">{props.label}</div>
<div className="ez-extra-actions__content">
<InstantFilter items={props.languageItems} handleItemChange={props.handleItemChange} />
</div>
</div>
);
};

LanguageSelector.propTypes = {
isOpen: PropTypes.bool,
label: PropTypes.string,
languageItems: PropTypes.array,
handleItemChange: PropTypes.func,
closeLanguageSelector: PropTypes.func,
};

LanguageSelector.defaultProps = {
isOpen: false,
label: '',
languageItems: [],
handleItemChange: () => {},
closeLanguageSelector: () => {},
};

export default LanguageSelector;
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React, { Component, createRef } from 'react';
import { createPortal } from 'react-dom';
import PropTypes from 'prop-types';

import TableViewItemComponent from './table.view.item.component';
import TableViewColumnsTogglerComponent from './table.view.columns.toggler';
import ThreeStateCheckboxComponent from '../three-state-checkbox/three.state.checkbox.component';
import LanguageSelector from '../sub-items-list/language.selector.compoment';

const ACTION_COTAINER_SELECTOR = '.ez-extra-actions-container';
const COLUMNS_VISIBILITY_LOCAL_STORAGE_DATA_KEY = 'sub-items_columns-visibility';
const DEFAULT_COLUMNS_VISIBILITY = {
modified: true,
Expand Down Expand Up @@ -53,11 +56,16 @@ export default class TableViewComponent extends Component {
this.selectAll = this.selectAll.bind(this);
this.setColumnsVisibilityInLocalStorage = this.setColumnsVisibilityInLocalStorage.bind(this);
this.toggleColumnVisibility = this.toggleColumnVisibility.bind(this);
this.setLanguageSelectorData = this.setLanguageSelectorData.bind(this);
this.openLanguageSelector = this.openLanguageSelector.bind(this);
this.closeLanguageSelector = this.closeLanguageSelector.bind(this);

this._refColumnsTogglerButton = createRef();

this.state = {
columnsVisibility: this.getColumnsVisibilityFromLocalStorage(),
languageSelectorData: {},
languageSelectorOpen: false,
};
}

Expand Down Expand Up @@ -105,6 +113,31 @@ export default class TableViewComponent extends Component {
);
}

/**
* Sets language selector data
*
* @param {Object} data
*/
setLanguageSelectorData(data) {
this.setState({ languageSelectorData: data });
}

/**
* @method openLanguageSelector
* @memberof TableViewComponent
*/
openLanguageSelector() {
this.setState({ languageSelectorOpen: true });
}

/**
* @method closeLanguageSelector
* @memberof TableViewComponent
*/
closeLanguageSelector() {
this.setState({ languageSelectorOpen: false });
}

/**
* Renders single list item
*
Expand All @@ -129,6 +162,8 @@ export default class TableViewComponent extends Component {
onItemSelect={onItemSelect}
isSelected={isSelected}
columnsVisibility={columnsVisibility}
setLanguageSelectorData={this.setLanguageSelectorData}
openLanguageSelector={this.openLanguageSelector}
/>
);
}
Expand Down Expand Up @@ -223,6 +258,14 @@ export default class TableViewComponent extends Component {
<tbody className="c-table-view__body">{renderedItems}</tbody>
</table>
</div>
{createPortal(
<LanguageSelector
isOpen={this.state.languageSelectorOpen}
close={this.closeLanguageSelector}
{...this.state.languageSelectorData}
/>,
window.document.querySelector(ACTION_COTAINER_SELECTOR)
)}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export default class TableViewItemComponent extends PureComponent {
this.handleEdit = this.handleEdit.bind(this);
this.onSelectCheckboxChange = this.onSelectCheckboxChange.bind(this);
this.setPriorityInputRef = this.setPriorityInputRef.bind(this);
this.getLanguageSelectorData = this.getLanguageSelectorData.bind(this);
this.editItem = this.editItem.bind(this);

this._refPriorityInput = null;

Expand Down Expand Up @@ -106,25 +108,46 @@ export default class TableViewItemComponent extends PureComponent {
}

/**
* Handles edit action.
* Edit sub item
*
* @method handleEdit
* @method editItem
* @memberof TableViewItemComponent
*/
handleEdit() {
const { id, mainLanguageCode, currentVersion } = this.props.item.content._info;

this.props.handleEditItem({
_id: id,
mainLanguageCode,
CurrentVersion: {
Version: {
VersionInfo: {
versionNo: currentVersion.versionNumber,
editItem(languageCode) {
const { id, currentVersion } = this.props.item.content._info;

this.props.handleEditItem(
{
_id: id,
mainLanguageCode: languageCode,
CurrentVersion: {
Version: {
VersionInfo: {
versionNo: currentVersion.versionNumber,
},
},
},
},
}, this.props.item.id);
this.props.item.id
);
}

/**
* Handles edit action.
*
* @method handleEdit
* @memberof TableViewItemComponent
*/
handleEdit() {
const { mainLanguageCode, currentVersion } = this.props.item.content._info;
const { languageCodes } = currentVersion;

if (languageCodes.length > 1) {
this.props.setLanguageSelectorData(this.getLanguageSelectorData());
this.props.openLanguageSelector();
} else {
this.editItem(mainLanguageCode);
}
}

setPriorityInputRef(ref) {
Expand Down Expand Up @@ -288,6 +311,29 @@ export default class TableViewItemComponent extends PureComponent {
onItemSelect(item, isSelected);
}

/**
* Get data for language selector
*
* @method getLanguageSelectorData
* @returns {Object}
* @memberof TableViewItemComponent
*/
getLanguageSelectorData() {
const languages = this.props.languages.mappings;
const { languageCodes } = this.props.item.content._info.currentVersion;
const label = Translator.trans(/*@Desc("Select language")*/ 'languages.modal.label', {}, 'sub_items');
const languageItems = languageCodes.map((item) => ({
label: languages[item].name,
value: item,
}));

return {
languageItems,
label: `${label} (${languageItems.length})`,
handleItemChange: this.editItem,
};
}

render() {
const { item, isSelected } = this.props;
const editLabel = Translator.trans(/*@Desc("Edit")*/ 'edit_item_btn.label', {}, 'sub_items');
Expand Down

0 comments on commit 4dda573

Please sign in to comment.