Created
January 25, 2021 07:06
-
-
Save vytsci/438802120d16f9ec68298432590a6ea6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {get, forEach, size, snakeCase, unset} from "lodash"; | |
import {t} from "functions"; | |
import React from 'react'; | |
import { | |
FlexboxGrid, | |
Modal, | |
ButtonToolbar, | |
ButtonGroup, | |
IconButton, | |
Icon, | |
Placeholder, | |
Button, | |
Loader, | |
Drawer, | |
Form, | |
Divider, | |
FormGroup, | |
TagGroup, | |
Table, | |
Tag | |
} from 'rsuite'; | |
import moment from "moment"; | |
import API from "modules/api"; | |
export default class Datagrid extends React.Component { | |
constructor(props = {options: {}}) { | |
super(props); | |
// Stateless properties | |
this.resource = props.resource; | |
this.options = props.options; | |
this.toolbar = props.toolbar; | |
this.filter = props.filter; | |
this.actions = props.actions; | |
this.state = { | |
// Datagrid states | |
error: null, | |
isLoaded: false, | |
isLoading: false, | |
// Filter states | |
filterShow: false, | |
filterValue: {}, | |
filterTags: [], | |
// Table states | |
activePage: 1, | |
displayLength: 30, | |
total: 0, | |
data: [], | |
columns: props.columns, | |
}; | |
} | |
/** | |
* | |
*/ | |
componentDidMount() { | |
this.reload(); | |
} | |
/** | |
* Reloads data from API based on collected parameters | |
* | |
* @param activePage | |
* @param displayLength | |
*/ | |
reload(activePage = this.state.activePage, displayLength = this.state.displayLength) { | |
this.setState({isLoading: true}); | |
const params = { | |
"page": activePage, | |
"per_page": displayLength, | |
}; | |
// Lets build filter params | |
if (size(this.state.filterValue) > 0) { | |
forEach(this.state.filterValue, (value, name) => { | |
params[`filter[${name}]`] = value; | |
}); | |
} | |
API.get( | |
this.resource, | |
Object.assign({"params": params}, this.options), | |
(data, meta) => { | |
this.setState({ | |
isLoaded: true, | |
isLoading: false, | |
data: data, | |
activePage: meta.pagination.current_page, | |
displayLength: meta.pagination.per_page, | |
total: meta.pagination.total, | |
}); | |
}, | |
(error) => { | |
this.setState({ | |
isLoaded: true, | |
error | |
}); | |
} | |
); | |
} | |
/** | |
* Pops filter up | |
*/ | |
showFilter() { | |
this.setState({filterShow: true}); | |
} | |
/** | |
* Closes filter | |
*/ | |
closeFilter() { | |
this.setState({filterShow: false}); | |
} | |
/** | |
* Handles filter changes | |
* | |
* @param filterValue | |
*/ | |
handleFilterChange(filterValue) { | |
this.setState({filterValue: filterValue, renderFilterTags: false}); | |
} | |
/** | |
* Handles filter submission | |
*/ | |
handleFilterSubmit() { | |
this.setState({filterShow: false, filterShowTags: true}); | |
this.reload(); | |
} | |
/** | |
* Handles filter tag removal | |
* | |
* @param name | |
*/ | |
handleFilterTagRemove(name) { | |
const {filterValue} = this.state; | |
if (unset(filterValue, name)) { | |
this.setState({filterValue: filterValue}); | |
} | |
this.reload(); | |
} | |
/** | |
* Renders filter tags | |
* | |
* @returns {[]} | |
*/ | |
renderFilterTags() { | |
const tags = []; | |
if (this.state.filterShowTags && size(this.state.filterValue) > 0) { | |
forEach(this.state.filterValue, (value, name) => { | |
tags.push( | |
<Tag key={name} onClose={() => {this.handleFilterTagRemove(name);}} closable> | |
{t(`datagrid.filter.${name}.label`)}: "{value}" | |
</Tag> | |
); | |
}); | |
} | |
return tags; | |
} | |
/** | |
* Handles table properties change | |
* | |
* @param activePage | |
* @param displayLength | |
*/ | |
handleTableChange(activePage = 1, displayLength = this.props.displayLength) { | |
this.setState({activePage: activePage, displayLength: displayLength}); | |
} | |
/** | |
* Renders table columns | |
* | |
* @returns {[]} | |
*/ | |
renderTableColumns() { | |
const columns = []; | |
forEach(this.state.columns, (column, name) => { | |
columns.push( | |
<Table.Column key={name} fixed={true} flexGrow={1}> | |
<Table.HeaderCell>{t(`datagrid.column.${name}`)}</Table.HeaderCell> | |
<Table.Cell dataKey={name}> | |
{(rowData, rowIndex) => { | |
let cellData = get(rowData, column.value); | |
if (column.translate) { | |
cellData = t(`datagrid.cell.${column.value}.${snakeCase(cellData)}`); | |
} | |
if (moment(cellData, moment.ISO_8601, true).isValid()) { | |
cellData = moment(cellData).locale("lt").format("LLL"); | |
} | |
if (column.color) { | |
cellData = <span style={{color: get(rowData, column.color)}}>{cellData}</span>; | |
} | |
return cellData; | |
}} | |
</Table.Cell> | |
</Table.Column> | |
); | |
}); | |
return columns; | |
} | |
/** | |
* Renders whole component | |
* | |
* @returns {JSX.Element} | |
*/ | |
render() { | |
let loader = <Loader backdrop content={t("Loading")} vertical />; | |
if (this.state.error) { | |
return <div>Error: {this.state.error.message}</div>; | |
} | |
if (!this.state.isLoaded) { | |
return ( | |
<div> | |
<Placeholder.Grid rows={5} columns={6} active /> | |
<Loader backdrop content={t("Loading")} vertical /> | |
</div> | |
); | |
} | |
if (!this.state.isLoading) { | |
loader = null; | |
} | |
return ( | |
<div> | |
<ButtonToolbar> | |
<FlexboxGrid justify="space-between"> | |
<ButtonGroup> | |
{this.toolbar} | |
</ButtonGroup> | |
<ButtonGroup> | |
<IconButton | |
icon={<Icon icon="angle-left" />} | |
onClick={() => this.showFilter()} | |
> | |
{t("common.filter.label")} | |
</IconButton> | |
</ButtonGroup> | |
</FlexboxGrid> | |
</ButtonToolbar> | |
<Drawer | |
size="md" | |
placement="right" | |
show={this.state.filterShow} | |
onHide={() => this.closeFilter()} | |
> | |
<Drawer.Header> | |
<Drawer.Title>{t("datagrid.filter.label")}</Drawer.Title> | |
</Drawer.Header> | |
<Drawer.Body> | |
<div> | |
<Form | |
ref={ref => (this.filterForm = ref)} | |
onChange={filterValue => {this.handleFilterChange(filterValue)}} | |
formDefaultValue={this.state.filterValue} | |
fluid | |
> | |
{this.filter} | |
<FormGroup> | |
<FlexboxGrid justify="end"> | |
<FlexboxGrid.Item> | |
<ButtonToolbar> | |
<Button appearance="default" placement="right" onClick={() => this.closeFilter()}>{t("common.close.label")}</Button> | |
<Button appearance="primary" placement="right" onClick={() => this.handleFilterSubmit()}>{t("common.submit.label")}</Button> | |
</ButtonToolbar> | |
</FlexboxGrid.Item> | |
</FlexboxGrid> | |
</FormGroup> | |
</Form> | |
</div> | |
</Drawer.Body> | |
</Drawer> | |
<FlexboxGrid justify="center" style={{marginTop: 10, marginBottom: 10}}> | |
<FlexboxGrid.Item> | |
<TagGroup> | |
{this.renderFilterTags()} | |
</TagGroup> | |
</FlexboxGrid.Item> | |
</FlexboxGrid> | |
<Table | |
autoHeight={true} | |
data={this.state.data} | |
onRowClick={data => { | |
console.log(data); | |
}} | |
> | |
{this.renderTableColumns()} | |
<Table.Column fixed="right" flexGrow={1}> | |
<Table.HeaderCell>{t("datagrid.column.actions")}</Table.HeaderCell> | |
<Table.Cell dataKey="actions"> | |
{rowData => { | |
if (typeof this.actions === "function") { | |
return <ButtonToolbar>{this.actions(rowData)}</ButtonToolbar>; | |
} | |
}} | |
</Table.Cell> | |
</Table.Column> | |
</Table> | |
<Table.Pagination | |
activePage={this.state.activePage} | |
displayLength={this.state.displayLength} | |
first={true} | |
last={true} | |
next={true} | |
onChangeLength={eventKey => this.handleTableChange(1, eventKey)} | |
onChangePage={eventKey => this.handleTableChange(eventKey)} | |
prev={true} | |
total={this.state.total} | |
/> | |
{loader} | |
</div> | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {t} from "functions"; | |
import React from 'react'; | |
import ReactDOM from 'react-dom'; | |
import Datagrid from "components/restful/datagrid.jsx"; | |
import 'rsuite/lib/styles/index.less'; | |
import { | |
Col, | |
ControlLabel, | |
DatePicker, | |
FormControl, | |
FormGroup, | |
Grid, | |
Icon, | |
IconButton, | |
Row, | |
Tooltip, | |
Whisper | |
} from "rsuite"; | |
function view() { | |
console.log("view"); | |
} | |
function edit() { | |
console.log("edit"); | |
} | |
function remove() { | |
console.log("remove"); | |
} | |
function Root() { | |
return ( | |
<Grid fluid style={{width: "97%"}}> | |
<Row> | |
<Col xs={24}> | |
<Datagrid | |
resource={"rest/tickets/tickets"} | |
columns={{ | |
"id": {"value": "id"}, | |
"subject": {"value": "subject"}, | |
"created_at": {"value": "created_at"}, | |
"updated_at": {"value": "updated_at"}, | |
"category": {"value": "category.name", "color": "category.color"}, | |
"state": {"value": "state", "color": "state_color", "translate": true}, | |
}} | |
toolbar={[ | |
<IconButton | |
key="add" | |
icon={<Icon icon="plus" />} | |
color={"blue"} | |
onClick={() => view()} | |
> | |
{t("datagrid.toolbar.add.label")} | |
</IconButton> | |
]} | |
filter={[ | |
<FormGroup key="search"> | |
<ControlLabel>{t("tickets.filter.search.label")}</ControlLabel> | |
<Whisper trigger="focus" speaker={<Tooltip>{t("tickets.filter.search.help")}</Tooltip>}> | |
<FormControl name="search"/> | |
</Whisper> | |
</FormGroup>, | |
<FormGroup key="category"> | |
<ControlLabel>{t("tickets.filter.category.label")}</ControlLabel> | |
<Whisper trigger="focus" speaker={ | |
<Tooltip>{t("tickets.filter.category.help")}</Tooltip>}> | |
<FormControl name="category" accepter={AutoComplete}/> | |
</Whisper> | |
</FormGroup>, | |
<FormGroup key="crated_range" style={{overflowX: "hidden"}}> | |
<Row gutter={8}> | |
<Col xs={12}> | |
<ControlLabel>{t("tickets.filter.created_after.label")}</ControlLabel> | |
<FormControl name="created_after" accepter={DatePicker} format="YYYY-MM-DD HH:mm:ss" block/> | |
</Col> | |
<Col xs={12}> | |
<ControlLabel>{t("tickets.filter.created_before.label")}</ControlLabel> | |
<FormControl name="created_before" accepter={DatePicker} format="YYYY-MM-DD HH:mm:ss" block/> | |
</Col> | |
</Row> | |
</FormGroup> | |
]} | |
actions={(rowData) => [ | |
<IconButton key="view" size="xs" onClick={(rowData) => view(rowData)} icon={<Icon icon="eye" />} color="blue" circle title={t("datagrid.action.view")} />, | |
<IconButton key="edit" size="xs" onClick={(rowData) => edit(rowData)} icon={<Icon icon="edit" />} color="orange" circle title={t("datagrid.action.edit")} />, | |
<IconButton key="delete" size="xs" onClick={(rowData) => remove(rowData)} icon={<Icon icon="trash" />} color="red" circle title={t("datagrid.action.delete")} /> | |
]} | |
/> | |
</Col> | |
</Row> | |
</Grid> | |
); | |
} | |
ReactDOM.render(<Root />, document.getElementById('root')); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment