Last active
August 17, 2017 05:54
-
-
Save Tushant/4f9a05e79b8eb9d9d528385cd1c54efd 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
class Pagination extends React.Component { | |
static defaultProps = { | |
initialPage: 1 | |
}; | |
constructor(props) { | |
super(props); | |
this.state = { pager: {}, totalItems: this.props.totalItems }; | |
} | |
componentDidMount() { | |
// set page if items array isn't empty | |
if (this.props.items) { | |
this.setPage(this.props.initialPage); | |
} | |
} | |
componentWillReceiveProps(nextProps, nextState) { | |
if (nextProps.items !== this.props.items) { | |
console.log("pager"); | |
this.setState({ totalItems: nextProps.totalItems }, () => | |
this.setPage(this.props.initialPage) | |
); | |
} | |
if (nextProps.totalItems !== this.props.totalItems) { | |
this.setState({ totalItems: nextProps.totalItems }, () => | |
this.setPage(this.props.initialPage) | |
); | |
} | |
} | |
setPage(page) { | |
let items = this.props.items; | |
let pager = this.state.pager; | |
if (page < 1 || page > pager.totalPages) { | |
return; | |
} | |
// get new pager object for specified page | |
pager = this.getPager(this.state.totalItems, page); | |
// update state | |
this.setState({ pager: pager }, () => | |
this.props.onChangePage(pager.currentPage, pager.pageSize) | |
); | |
} | |
getPager(totalItems, currentPage, pageSize) { | |
// default to first page | |
currentPage = currentPage || 1; | |
// default page size is 10 | |
pageSize = pageSize || 10; | |
// calculate total pages | |
const totalPages = Math.ceil(totalItems / pageSize); | |
let startPage, endPage; | |
if (totalPages <= 10) { | |
// less than 10 total pages so show all | |
startPage = 1; | |
endPage = totalPages; | |
} else { | |
// more than 10 total pages so calculate start and end pages | |
if (currentPage <= 6) { | |
startPage = 1; | |
endPage = 10; | |
} else if (currentPage + 4 >= totalPages) { | |
startPage = totalPages - 9; | |
endPage = totalPages; | |
} else { | |
startPage = currentPage - 5; | |
endPage = currentPage + 4; | |
} | |
} | |
// calculate start and end item indexes | |
let startIndex = (currentPage - 1) * pageSize; | |
let endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1); | |
let pages = range(startPage, endPage + 1); | |
// return object with all pager properties required by the view | |
return { | |
totalItems: totalItems, | |
currentPage: currentPage, | |
pageSize: pageSize, | |
totalPages: totalPages, | |
startPage: startPage, | |
endPage: endPage, | |
startIndex: startIndex, | |
endIndex: endIndex, | |
pages: pages | |
}; | |
} | |
render() { | |
const { pager } = this.state; | |
return ( | |
<ul style={{ display: "inherit" }}> | |
<li className={pager.currentPage === 1 ? "disable" : ""}> | |
<a className="icon item" onClick={() => this.setPage(1)}> | |
<i className="icon-skip_previous" /> | |
</a> | |
</li> | |
<li className={pager.currentPage === 1 ? "disable" : ""}> | |
<a | |
className="icon item" | |
onClick={() => this.setPage(pager.currentPage - 1)} | |
> | |
<i className="icon-keyboard_arrow_left" /> | |
</a> | |
</li> | |
{ | |
pager.pages.map((page, index) => | |
<li | |
key={index} | |
className={pager.currentPage === page ? "active-page" : ""} | |
> | |
<a className="item" onClick={() => this.setPage(page)}> | |
{page} | |
</a> | |
</li> | |
)} | |
<li className={pager.currentPage === pager.totalPages ? "disable" : ""}> | |
<a | |
className="icon item" | |
onClick={() => this.setPage(pager.currentPage + 1)} | |
> | |
<i className="icon-keyboard_arrow_right" /> | |
</a> | |
</li> | |
<li className={pager.currentPage === pager.totalPages ? "disable" : ""}> | |
<a | |
className="icon item" | |
onClick={() => this.setPage(pager.totalPages)} | |
> | |
<i className="icon-skip_next" /> | |
</a> | |
</li> | |
</ul> | |
); | |
} | |
} | |
export default Pagination; |
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 React from "react"; | |
import Link from "react-router-dom/Link"; | |
import { Label, Menu, Table } from "semantic-ui-react"; | |
import { capitalize } from "utils/helper"; | |
import { isEmpty } from "utils/helper"; | |
import Pagination from "./Pagination"; | |
const perPageToShow = 10; | |
const step = 3; | |
const style = { | |
paginationBtn: { | |
padding: 0, | |
border: 0, | |
borderRadius: 0, | |
margin: 0, | |
background: "rgba(26, 179, 148, 0.8)" | |
}, | |
btnText: { | |
color: "#fff" | |
} | |
}; | |
function evalValue(value, header) { | |
if (value === true) { | |
return <i className="icon-check" />; | |
} | |
if (value === false) { | |
return <i className="icon-close" />; | |
} | |
if (Array.isArray(value) && value.length > 1) { | |
return capitalize(value.join(", ")); | |
} | |
if (typeof value === "string" && value.indexOf("@") > -1) { | |
return String(value); | |
} | |
if (header.type === "icon") { | |
return header.icon.map(ico => { | |
if (ico.name.toLowerCase() === value.toLowerCase()) { | |
return ( | |
<div className="has-icon" key={ico.name}> | |
<i className={ico.icon} /> | |
{capitalize(String(ico.name))} | |
</div> | |
); | |
} | |
}); | |
} | |
return capitalize(String(value)); | |
} | |
function evalActions(data, action, action_id, onDelete, showModal) { | |
if (action.type === "view") { | |
let url; | |
if (action_id) { | |
url = | |
action.action && | |
(data[action_id] | |
? action.action + "/" + data[action_id] | |
: action.action); | |
} else if (!action_id) { | |
url = | |
action.action && | |
(data._id ? action.action + "/" + data._id : action.action); | |
} | |
return ( | |
<Link to={url}> | |
<i className={action.icon} /> | |
</Link> | |
); | |
} | |
if (action.type === "modal") { | |
return <i className={action.icon} onClick={() => showModal(data._id)} />; | |
} | |
if (action.type === "delete") { | |
// event is used | |
return <i className={action.icon} onClick={() => onDelete(data._id)} />; | |
} | |
} | |
// here field is for first-level key of object, and fieldName is for nested key | |
// eg: { field: { fieldName: ''}} | |
// for simple case { field: ''} | |
function cellToShow(data, headers, actions, action_id, onDelete, showModal) { | |
if (data && !isEmpty(data)) { | |
return data.map(datum => { | |
return ( | |
<Table.Row key={datum._id}> | |
{headers.map(header => { | |
return ( | |
<Table.Cell key={header.key}> | |
{evalValue( | |
header.fieldName | |
? datum[header.field][header.fieldName] | |
: datum[header.field], | |
header | |
)} | |
</Table.Cell> | |
); | |
})} | |
{actions && | |
actions.map(action => | |
<Table.Cell key={action.key} className="action"> | |
{evalActions(datum, action, action_id, onDelete, showModal)} | |
</Table.Cell> | |
)} | |
</Table.Row> | |
); | |
}); | |
} | |
} | |
function headerToShow(headers) { | |
return headers.map(header => | |
<Table.HeaderCell key={header.key}> | |
{header.name} | |
</Table.HeaderCell> | |
); | |
} | |
class CustomTable extends React.PureComponent { | |
constructor(props) { | |
super(props); | |
this.state = { | |
pageOfItems: [], | |
items: this.props.data | |
}; | |
} | |
onChangePage = (currentPage, pageSize) => { | |
this.props.onPaginate(currentPage, pageSize); | |
}; | |
render() { | |
const { | |
headers, | |
data, | |
actions, | |
pagination, | |
onDelete, | |
onPaginate, | |
action_id, | |
showModal | |
} = this.props; | |
const colSpanLength = headers.length + 1; | |
console.log("pagination totalitems is", pagination.get("totalItems")); | |
console.log("######################"); | |
return ( | |
<Table celled stackable sortable> | |
<Table.Header> | |
<Table.Row> | |
{headerToShow(headers)} | |
<Table.HeaderCell colSpan={actions && actions.length}> | |
Actions | |
</Table.HeaderCell> | |
</Table.Row> | |
</Table.Header> | |
{data && (data.length > 0 || data.size > 0) | |
? <Table.Body> | |
{cellToShow( | |
data, | |
headers, | |
actions, | |
action_id, | |
onDelete, | |
showModal | |
)} | |
</Table.Body> | |
: <Table.Body> | |
<Table.Row> | |
<Table.Cell>No data</Table.Cell> | |
</Table.Row> | |
</Table.Body>} | |
{data && | |
(data.length > 0 || data.size > 0) && | |
pagination && | |
<Table.Footer> | |
<Table.Row> | |
<Table.HeaderCell colSpan={colSpanLength}> | |
<Menu floated="right" pagination> | |
{/* <Pagination | |
items={this.state.items && this.state.items} | |
onChangePage={(currentPage, pageSize) => | |
this.onChangePage(currentPage, pageSize)} | |
totalItems={ | |
pagination.get("totalItems") || pagination.totalItems | |
} | |
initialPage={ | |
this.props.initialPage ? this.props.initialPage : 1 | |
} | |
/> */} | |
</Menu> | |
</Table.HeaderCell> | |
</Table.Row> | |
</Table.Footer>} | |
</Table> | |
); | |
} | |
} | |
export default CustomTable; |
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 React from "react"; | |
import Toaster from "components/Toaster"; | |
import { createStructuredSelector } from "reselect"; | |
import { connect } from "react-redux"; | |
import debounce from "lodash/debounce"; | |
import { showDialog } from "containers/App/actions"; | |
import { makeSelectDialog } from "containers/App/selectors"; | |
import { loadUsers, deleteUser } from "./actions"; | |
import { | |
makeSelectUsers, | |
makeSelectSuccessResponse, | |
makeSelectErrorResponse, | |
makeSelectPagination, | |
makeSelectLoading | |
} from "./selectors"; | |
import DeleteConfirmation from "components/DeleteConfirmation"; | |
import UsersTable from "./UsersTable"; | |
const perPageToShow = 10; | |
const mapDispatchToProps = dispatch => ({ | |
fetchUser: (name, page, perPage) => dispatch(loadUsers(name, page, perPage)), | |
deleteUser: userId => dispatch(deleteUser(userId)), | |
showDialog: dialog => dispatch(showDialog(dialog)), | |
hideDialog: () => dispatch(showDialog(null)) | |
}); | |
const mapStateToProps = createStructuredSelector({ | |
users: makeSelectUsers(), | |
paginationParams: makeSelectPagination(), | |
successResponse: makeSelectSuccessResponse(), | |
errorResponse: makeSelectErrorResponse(), | |
isRequesting: makeSelectLoading(), | |
dialog: makeSelectDialog() | |
}); | |
class UserList extends React.PureComponent { | |
constructor(props) { | |
super(props); | |
this.state = { show: false, item: "", page: 1, usersData: {} }; | |
} | |
componentDidMount() { | |
this.props.fetchUser("", 1, perPageToShow); | |
} | |
componentWillReceiveProps(nextProps) { | |
console.log("paginationParams", nextProps.paginationParams); | |
if (nextProps.paginationParams !== this.props.paginationParams) { | |
this.setState({ pagination: nextProps.paginationParams }); | |
} | |
} | |
componentWillMount() { | |
const { totalItems, currentPage } = this.props.paginationParams; | |
this.delayedSearch = debounce(item => { | |
this.props.fetchUser(this.state.item, this.state.page, totalItems); | |
}, 1000); | |
} | |
deleteRow(cell) { | |
this.setState({ show: true }); | |
if (cell) { | |
const userDeleteConfirmation = ( | |
<DeleteConfirmation | |
hideDialog={this.props.hideDialog} | |
deleteKey={cell} | |
text="user" | |
onDelete={this.props.deleteUser} | |
/> | |
); | |
this.props.showDialog(userDeleteConfirmation); | |
} | |
} | |
handlePagination(page, pageSize) { | |
this.setState({ page }); | |
this.props.fetchUser(this.state.item || "", page, pageSize); | |
} | |
doSearch(item) { | |
this.setState({ item }, () => this.delayedSearch(this.state.item)); | |
} | |
render() { | |
const { | |
users, | |
successResponse, | |
errorResponse, | |
paginationParams | |
} = this.props; | |
let message; | |
if (successResponse && typeof successResponse === "string") { | |
message = <Toaster message={successResponse} timeout={1000} success />; | |
} | |
if (errorResponse && typeof errorResponse === "string") { | |
message = <Toaster message={errorResponse} timeout={1000} error />; | |
} | |
const headers = [ | |
{ name: "First Name", field: "first_name", sorted: true, key: 1 }, | |
{ name: "Email", field: "email", key: 2 }, | |
{ name: "Role", field: "user_role", key: 3 }, | |
{ name: "Email Verified", field: "confirmed", sorted: true, key: 4 } | |
]; | |
const actions = [ | |
{ | |
key: 1, | |
name: "view", | |
type: "view", | |
icon: "icon icon-eye", | |
action: "/admin/dashboard/user" | |
}, | |
{ | |
key: 2, | |
name: "delete", | |
type: "delete", | |
icon: "icon icon-trash" | |
} | |
]; | |
return ( | |
<div className="left container"> | |
{message && message} | |
{this.state.show ? this.props.dialog : null} | |
<h1>Users</h1> | |
<UsersTable | |
searchItems={item => this.doSearch(item)} | |
headers={headers} | |
data={users && users.toJS()} | |
actions={actions} | |
onDelete={cell => this.deleteRow(cell)} | |
pagination={paginationParams && paginationParams} | |
onPaginate={(page, pageSize) => this.handlePagination(page, pageSize)} | |
isRequesting={this.props.isRequesting} | |
/> | |
</div> | |
); | |
} | |
} | |
export default connect(mapStateToProps, mapDispatchToProps)(UserList); |
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 React from "react"; | |
import CustomTable from "components/Table"; | |
import SearchBox from "components/SearchBox"; | |
import Loader from "components/Loader/SpecificLoader"; | |
import { sizeOfAnObject } from "utils/helper"; | |
const UsersTable = ({ | |
searchItems, | |
headers, | |
data, | |
actions, | |
onDelete, | |
pagination, | |
onPaginate, | |
isRequesting, | |
...props | |
}) => { | |
if (sizeOfAnObject(data) <= 0 || data.length <= 0) { | |
return <Loader />; | |
} | |
return ( | |
<div> | |
<SearchBox searchItems={searchItems} /> | |
<CustomTable | |
headers={headers} | |
data={data && data} | |
actions={actions} | |
onDelete={onDelete} | |
pagination={pagination} | |
onPaginate={onPaginate} | |
/> | |
</div> | |
); | |
}; | |
export default Loader('isRequesting')(UsersTable); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment