fk-react-ui-components
Version:
Step 1 : Create a file in [ Seeds / Plants / Trees ] <br> Step 2 : It should export an Object with component name and story Component [Refer other components] <br> Step 3 : Story Component should return a react component <br> Step 3 : Created file should
311 lines (273 loc) • 10.8 kB
JavaScript
/**
* Created by sarunathan.s
*/
import React from 'react';
import _ from 'lodash';
import Icon from '../StyleComponents/icon';
import { SecondaryBtn } from '../Fields';
import {
Table,
TheadCell,
TbodyCell,
GridDetail,
GridContainer,
DetailHeader,
DetailContent,
NoDataTr,
Loader
} from './style.js';
import { colors } from '../colorCodes';
const loaderMinWidth = 60;
const loaderMaxWidth = 110;
class Grid extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedCheckBox : {},
showDetails : false,
detailsLeftPx: null,
selectedId:""
}
}
componentDidMount() {
if (this.state.detailsLeftPx == null) {
this.setState({
detailsLeftPx: this.computeDetailLeft()
});
}
}
componentWillReceiveProps(nextProps) {
this.props.selectRow && this.resetSelectedHandler(nextProps.data); // When data changes if the new id is not in render remove from selected array
if( !_.isEqual(this.props.data,nextProps.data) ){
this.disableDetailsView();
}
}
componentDidUpdate(prevProps, prevState) {
if (
!_.isEqual(
prevState.selectedCheckBox,
this.state.selectedCheckBox
) &&
this.props.checkBoxOnchange
) {
this.props.checkBoxOnchange(
Object.keys(this.state.selectedCheckBox)
);
}
}
getDataUniqueIds(data) {
return data.reduce((arr, obj) => {
arr[_.get(obj, this.props.id)] = 'selected';
return arr;
}, {});
}
sortableColumn(v, k) {
if (
this.props.sortableColumn &&
this.props.sortableColumn.indexOf(v.name) !== -1
) {
let icon;
if(this.state.sortApplied && this.state.sortApplied[v.name] && this.state.sortApplied[v.name] == "ascending"){
icon = <Icon className="fa fa-sort-asc clickable" width="15px" height="15px"/>;
}else if(this.state.sortApplied && this.state.sortApplied[v.name] && this.state.sortApplied[v.name] == "descending"){
icon = <Icon className="fa fa-sort-desc clickable" width="15px" height="15px"/>;
}else {
icon = <Icon className="fa fa-sort clickable" width="15px" height="15px"/>;
}
return <TheadCell key={k} className="clickable" onClick= {this.sortHandler.bind(this,v.name)}>{v.name}
{icon}
</TheadCell>
}
return <TheadCell key={k}>{v.name}</TheadCell>
}
sortHandler(key) {
this.setState(state => {
const sortApplied = {};
if (state.sortApplied && !state.sortApplied[key]) {
sortApplied[key] = 'descending';
this.props.sortOnchange && this.props.sortOnchange(sortApplied);
return {
sortApplied
};
}
if (state.sortApplied && state.sortApplied[key] == 'ascending') {
sortApplied[key] = 'descending';
} else {
sortApplied[key] = 'ascending';
}
this.props.sortOnchange && this.props.sortOnchange(sortApplied);
return {
sortApplied
};
});
}
resetSelectedHandler(data) {
const ids = this.getDataUniqueIds(data);
this.setState(prev => {
Object.keys(prev.selectedCheckBox)
.filter(id => !ids[id])
.forEach(id => {
delete prev.selectedCheckBox[id];
});
return prev;
})
}
selectAllCheckbox(e) {
const isSelect = e.target.checked;
let ids = this.getDataUniqueIds(this.props.data);
this.tableRef.querySelectorAll('.child-checkbox').forEach(o => {
o.checked = e.target.checked;
});
this.setState(prev=>{
if(!isSelect) ids = {} // return empty ids to state on deselect;
return {
...prev,
selectedCheckBox : {...ids}
}
})
}
computeDetailLeft() {
const ths = this.tableRef.querySelectorAll('th');
let width = 0;
let colToShow = this.props.colToShow || 1;
if (this.props.selectRow) ++colToShow;
[...Array(colToShow)].forEach((v, i) => {
width += ths[i].offsetWidth;
});
width = this.tableRef.offsetWidth/2 - width;
return `${width}px`;
}
enableDetailsView(id){
this.setState({
showDetails : true,
selectedId : id
})
}
disableDetailsView(){
this.setState({
showDetails : false,
selectedId : ""
})
}
chechBoxClickHandler(id) {
this.setState(prev => {
const prevState = _.cloneDeep(prev);
if (prevState.selectedCheckBox[id]) {
delete prevState.selectedCheckBox[id];
} else {
prevState.selectedCheckBox[id] = 'selected';
}
return prevState;
});
}
renderTableCell(obj, k, col, i) {
if( (_.get(obj,col.key) || !col.key) && this.props.enableDetailsView && col.clickable){
return <TbodyCell key={i} className="clickable" onClick={this.enableDetailsView.bind(this, _.get(obj, col.key) )}>
{this.props.cellRenderer ? this.props.cellRenderer( _.get(obj,col.key),{ row: k,column: i} ) : _.get(obj, col.key)}
</TbodyCell>
}
if( _.get(obj,col.key) || !col.key ){
return <TbodyCell key={i}>
{this.props.cellRenderer ? this.props.cellRenderer( _.get(obj,col.key),{ row: k,column: i} ) : _.get(obj, col.key)}
</TbodyCell>
}
return <TbodyCell key={i}>
{this.renderLoader()}
</TbodyCell>
}
renderLoader(){
const width = Math.random() * (loaderMaxWidth -loaderMinWidth) + loaderMinWidth;
return <Loader /*width={width+'px'}*//>
}
render() {
return (
<GridContainer left={this.state.detailsLeftPx}>
<div
className="grid-container" style={{width:"200%"}}
ref={el => {
this.tableRef = el;
}}
>
<Table>
<thead>
<tr>
{this.props.selectRow && (
<TheadCell className="checkbox-td">
<input
type="checkbox"
onClick={this.selectAllCheckbox.bind(
this
)}
/>
</TheadCell>
)}
{
this.props.column.map(this.sortableColumn.bind(this))
}
</tr>
</thead>
<tbody>
{this.props.data.map((obj, k) => (
<tr
className={
this.state.selectedId ===
_.get(obj, this.props.id)
? 'active'
: ''
}
key={_.get(obj, this.props.id)}
>
{this.props.selectRow && (
<TbodyCell className="checkbox-td">
<input
className="child-checkbox"
type="checkbox"
onClick={this.chechBoxClickHandler.bind(
this,
_.get(obj, this.props.id)
)}
/>
</TbodyCell>
)}
{this.props.column.map(this.renderTableCell.bind(this,obj,k))}
</tr>
))}
{(this.props.data.length === 0) && <NoDataTr>
<td colSpan="5">No data to display</td>
</NoDataTr> }
</tbody>
</Table>
<GridDetail
className={this.state.showDetails ? 'grid-detail' : ''}
>
<DetailHeader>
<SecondaryBtn
cursor="pointer"
padding="6px 10px"
textALign="left"
width="151px"
height="30px"
onClick={this.disableDetailsView.bind(this)}
>
<Icon
className="fa fa-angle-left clickable"
color={colors.brandBlue}
style={{ fontSize: '15px' }}
width="10px"
height="9px"
/>
Back to dashboard
</SecondaryBtn>
{this.props.detailViewHeader}
</DetailHeader>
<DetailContent>
{this.state.showDetails?this.props.detailViewContent:""}
</DetailContent>
</GridDetail>
<div style={{clear:"both"}}></div>
</div>
</GridContainer>
)
}
}
export default Grid