Skip to content

Commit

Permalink
OCLOMRS-58: paginate concepts in a dictionary (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
emasys authored and dkayiwa committed Jul 17, 2018
1 parent 129ace1 commit b3cbdcc
Show file tree
Hide file tree
Showing 19 changed files with 523 additions and 118 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"jsx-a11y/anchor-is-valid": 0,
"react/forbid-prop-types": 0,
"class-methods-use-this": "off",
"jsx-a11y/click-events-have-key-events": 0,
"compilerOptions": { "target": "ES6", "module": "commonjs" }
},
"parser": "babel-eslint"
Expand Down
4 changes: 2 additions & 2 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ const App = () => (
<Route exact path="/dashboard/dictionaries" component={Authenticate(DictionaryDisplay)} />
<Route exact path="/dashboard/userdictionaries" component={Authenticate(OwnerDictionary)} />
<Route exact path="/dashboard/concepts/:ownerType/:organization/:name" component={Authenticate(SpecificConcept)} />
<Route exact path="/concepts/:type/:typeName/:collectionName" component={Authenticate(DictionaryConcepts)} />
<Route exact path="/concepts/:type/:typeName/:collectionName/:dictionaryName" component={Authenticate(DictionaryConcepts)} />
<Route exact path="/dictionaryOverview/:ownerType/:owner/:type/:name" component={Authenticate(DictionaryOverview)} />
<Route exact path="/concepts/:type/:typeName/:collectionName/new/:conceptType?" component={Authenticate(CreateConcept)} />
<Route exact path="/concepts/:type/:typeName/:collectionName/:dictionaryName/new/:conceptType?" component={Authenticate(CreateConcept)} />
<Route component={NotFound} />
</Switch>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react';
import { Link } from 'react-router-dom';
import persistActiveconcept from './helperFunction';

const DictionaryCard = (dictionary) => {
const {
Expand Down Expand Up @@ -36,9 +35,8 @@ const DictionaryCard = (dictionary) => {
<div className="description col-12 text-left">
<p>
<Link
to={`/concepts${owner_url}${short_code}`}
to={`/concepts${owner_url}${short_code}/${name}`}
className="source-type"
onClick={() => persistActiveconcept(active_concepts)}
>
Concepts: { active_concepts }
</Link>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import { Link } from 'react-router-dom';
import './styles/dictionary-modal.css';
import persistActiveconcept from './helperFunction';

const DictionaryDetailCard = (dictionary) => {
const {
Expand Down Expand Up @@ -31,9 +30,7 @@ const DictionaryDetailCard = (dictionary) => {
<Link
className="btn btn-secondary"
id="conceptB"
to={`/concepts${owner_url}${short_code}`}
// this is a temporary fix, it will be optimized while working on paginations
onClick={() => persistActiveconcept(active_concepts)}
to={`/concepts${owner_url}${short_code}/${name}`}
>
Go to concepts
</Link>
Expand Down

This file was deleted.

8 changes: 5 additions & 3 deletions src/components/dictionaryConcepts/components/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';

const Header = ({ locationPath }) => {
const { type, typeName, collectionName } = locationPath;
const {
type, typeName, collectionName, dictionaryName,
} = locationPath;
return (
<section className="row concept-header">
<div className="col-12">
Expand All @@ -12,11 +14,11 @@ const Header = ({ locationPath }) => {
to={`/dictionaryOverview/${type}/${typeName}/collections/${collectionName}`}
className="collection-name small-text"
>
<i className="fas fa-chevron-left" /> Go back to {collectionName} dictionary
<i className="fas fa-chevron-left" /> Go back to {dictionaryName} dictionary
</Link>
</div>
<header>
<h2 className="text-capitalize">{collectionName} Dictionary</h2>
<h2 className="text-capitalize">{dictionaryName} Dictionary</h2>
</header>
</div>
</section>
Expand Down
83 changes: 60 additions & 23 deletions src/components/dictionaryConcepts/components/SearchBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,74 @@ import React from 'react';
import PropTypes from 'prop-types';

const SearchBar = ({
conceptsCount, totalConceptsCount, handleSearch, searchValue, submit,
}) => (
<div className="row search-container">
<div className="concept-search-wrapper col-12 col-md-5 col-sm-8">
<i className="fa fa-search search-icons" aria-hidden="true" />
<form action="" onSubmit={submit}>
<input
type="search"
name="searchInput"
className="concept-search"
id="search-concept"
value={searchValue}
onChange={handleSearch}
placeholder="search"
/>
</form>
conceptsCount,
totalConceptsCount,
handleSearch,
searchValue,
submit,
countStart,
prev,
next,
}) => {
const displayedConcepts = conceptsCount > totalConceptsCount ? totalConceptsCount : conceptsCount;
const togglePrevPaginationButton = !(countStart > 1);
const toggleNextPaginationButton = !(conceptsCount > totalConceptsCount);
return (
<div className="row search-container">
<div className="concept-search-wrapper col-12 col-md-5 col-sm-8">
<i className="fa fa-search search-icons" aria-hidden="true" />
<form action="" onSubmit={submit}>
<input
type="search"
name="searchInput"
className="concept-search"
id="search-concept"
value={searchValue}
onChange={handleSearch}
placeholder="search"
/>
</form>
</div>
<div className="search-pagination col-12">
<span className="paginate-count">
{countStart} - {displayedConcepts} of {totalConceptsCount}
<span className="paginate-controllers">
{!togglePrevPaginationButton && (
<i
className="fas fa-chevron-left left-arrow"
id="previous"
role="presentation"
onClick={prev}
/>
)}
{togglePrevPaginationButton && (
<i
className="fas fa-chevron-left left-arrow disabled-pagination-button"
role="presentation"
/>
)}
{toggleNextPaginationButton && (
<i className="fas fa-chevron-right" id="next" role="presentation" onClick={next} />
)}
{!toggleNextPaginationButton && (
<i className="fas fa-chevron-right disabled-pagination-button" role="presentation" />
)}
</span>
</span>
</div>
</div>
<div className="search-pagination col-12 col-md-5 offset-md-1 offset-lg-1 col-sm-5">
<span className="paginate-count">
Showing 1 - {conceptsCount} of {totalConceptsCount} concepts
</span>
</div>
</div>
);
);
};

SearchBar.propTypes = {
conceptsCount: PropTypes.number.isRequired,
totalConceptsCount: PropTypes.string.isRequired,
handleSearch: PropTypes.func.isRequired,
searchValue: PropTypes.string.isRequired,
submit: PropTypes.func.isRequired,
countStart: PropTypes.number.isRequired,
prev: PropTypes.func.isRequired,
next: PropTypes.func.isRequired,
};

export default SearchBar;
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export const getTotal = () => localStorage.getItem('total_concepts');
export const getUsername = () => localStorage.getItem('username');

export const classes = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,18 @@ export class CreateConcept extends Component {
componentWillReceiveProps(nextProps) {
const {
match: {
params: { collectionName, type, typeName },
params: {
collectionName, type, typeName, dictionaryName,
},
},
} = this.props;
const { newConcept, addedConcept } = nextProps;
const isNewConcept = Object.keys(newConcept).length;
const isAddedConcept = addedConcept.length;
if (isNewConcept && isAddedConcept) {
setTimeout(() => {
nextProps.history.push(`/concepts/${type}/${typeName}/${collectionName}`);
notify.show('concept successfully created', 'success', 3000);
nextProps.history.push(`/concepts/${type}/${typeName}/${collectionName}/${dictionaryName}`);
}, 3000);
}
}
Expand Down
83 changes: 50 additions & 33 deletions src/components/dictionaryConcepts/containers/DictionaryConcepts.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ import SideNav from '../components/Sidenav';
import SearchBar from '../components/SearchBar';
import ConceptTable from '../components/ConceptTable';
import { conceptsProps } from '../proptypes';
import { getTotal, getUsername } from '../components/helperFunction';
import { getUsername } from '../components/helperFunction';

import {
fetchDictionaryConcepts,
filterBySource,
filterByClass,
paginateConcepts,
} from '../../../redux/actions/concepts/dictionaryConcepts';

export class DictionaryConcepts extends Component {
Expand All @@ -37,60 +38,52 @@ export class DictionaryConcepts extends Component {
loading: PropTypes.bool.isRequired,
filterBySource: PropTypes.func.isRequired,
filterByClass: PropTypes.func.isRequired,
paginateConcepts: PropTypes.func.isRequired,
totalConceptCount: PropTypes.number.isRequired,
};

constructor(props) {
super(props);
this.state = {
conceptsCount: getTotal(),
conceptsCount: this.props.totalConceptCount,
searchInput: '',
conceptLimit: 10,
conceptOffset: 0,
};
autoBind(this);
}

componentDidMount() {
this.fetchConcepts();
}

componentWillReceiveProps(nextProps) {
const {
match: {
params: { collectionName, type, typeName },
},
} = this.props;
} = nextProps;
localStorage.setItem('dictionaryId', this.props.match.params.collectionName);
localStorage.setItem('type', this.props.match.params.type);
localStorage.setItem('typeName', this.props.match.params.typeName);
this.setState({ collectionName, type, typeName });
}

componentWillReceiveProps(nextProps) {
if (this.state.searchInput) {
this.setState({
conceptsCount: nextProps.concepts.length,
});
} else {
this.setState({
conceptsCount: getTotal(),
});
}
this.setState({
collectionName,
type,
typeName,
conceptsCount: nextProps.totalConceptCount,
});
}

fetchConcepts(query = '', limit = 10, filterParams = null, filterName = null) {
fetchConcepts(query = '', limit = 0, filterParams = null, filterName = null) {
const {
match: {
params: { collectionName, type, typeName },
},
} = this.props;
if (filterParams) {
this.props.filterBySource(
filterName,
type,
typeName,
collectionName,
query,
filterParams,
limit,
);
this.props.filterBySource(filterName, type, typeName, collectionName, query, limit);
}
this.props.fetchDictionaryConcepts(type, typeName, collectionName, query, filterParams, limit);
this.props.fetchDictionaryConcepts(type, typeName, collectionName, query, limit);
}

handleSearch(event) {
Expand All @@ -108,7 +101,6 @@ export class DictionaryConcepts extends Component {
this.state.type,
this.state.typeName,
this.state.collectionName,
filterType,
);
}
if (type === 'checkbox' && filterType === 'classes') {
Expand All @@ -117,7 +109,6 @@ export class DictionaryConcepts extends Component {
this.state.type,
this.state.typeName,
this.state.collectionName,
filterType,
);
}

Expand All @@ -137,6 +128,21 @@ export class DictionaryConcepts extends Component {
});
}

fetchNextConcepts() {
this.props.paginateConcepts(null, this.state.conceptLimit + 10, this.state.conceptOffset + 10);
this.setState(state => ({
conceptOffset: state.conceptOffset + 10,
conceptLimit: state.conceptLimit + 10,
}));
}
fetchPrevConcepts() {
this.props.paginateConcepts(null, this.state.conceptLimit - 10, this.state.conceptOffset - 10);
this.setState(state => ({
conceptOffset: state.conceptOffset - 10,
conceptLimit: state.conceptLimit - 10,
}));
}

render() {
const {
match: {
Expand All @@ -149,7 +155,9 @@ export class DictionaryConcepts extends Component {
loading,
} = this.props;
const username = typeName === getUsername();
const { conceptsCount, searchInput } = this.state;
const {
conceptsCount, searchInput, conceptOffset, conceptLimit,
} = this.state;
return (
<div className="container-fluid custom-dictionary-concepts">
<Header locationPath={this.props.match.params} />
Expand All @@ -169,11 +177,14 @@ export class DictionaryConcepts extends Component {
/>
<div className="col-12 col-md-10">
<SearchBar
conceptsCount={concepts.length}
conceptsCount={conceptLimit}
totalConceptsCount={conceptsCount}
handleSearch={this.handleSearch}
searchValue={searchInput}
submit={this.handleSubmit}
countStart={conceptOffset + 1}
next={this.fetchNextConcepts}
prev={this.fetchPrevConcepts}
/>
<ConceptTable concepts={concepts} loading={loading} />
</div>
Expand All @@ -184,7 +195,8 @@ export class DictionaryConcepts extends Component {
}

export const mapStateToProps = state => ({
concepts: state.concepts.dictionaryConcepts,
concepts: state.concepts.paginatedConcepts,
totalConceptCount: state.concepts.totalConceptCount,
filteredClass: state.concepts.filteredClass,
filteredSources: state.concepts.filteredSources,
loading: state.concepts.loading,
Expand All @@ -193,5 +205,10 @@ export const mapStateToProps = state => ({

export default connect(
mapStateToProps,
{ fetchDictionaryConcepts, filterBySource, filterByClass },
{
fetchDictionaryConcepts,
filterBySource,
filterByClass,
paginateConcepts,
},
)(DictionaryConcepts);
Loading

0 comments on commit b3cbdcc

Please sign in to comment.