add page loading action.
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
"react-overlays": "^1.2.0",
|
||||
"react-router-dom": "^5.0.0",
|
||||
"react-scripts": "3.0.1",
|
||||
"react-spinner-material": "^1.1.1",
|
||||
"react-transition-group": "^4.0.1",
|
||||
"typescript": "3.4.5"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
margin: 100px 0 0 0;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import Spinner from 'react-spinner-material';
|
||||
import styles from './Loading.module.css';
|
||||
|
||||
const Loading = () => {
|
||||
return (
|
||||
<div className={styles.loading}>
|
||||
<Spinner size={70} spinnerColor={'#cccccc'} spinnerWidth={8} visible={true} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Loading;
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { RouteComponentProps, withRouter } from 'react-router';
|
||||
|
||||
interface Props extends RouteComponentProps { }
|
||||
|
||||
@@ -33,7 +33,7 @@ class PageNotFound extends Component<Props> {
|
||||
</Helmet>
|
||||
<h1>Page Not Found</h1>
|
||||
<section>
|
||||
<p>The page you were trying to access doesn't exist or has been removed.</p>
|
||||
<p>The page you were trying to access doesn't exist.</p>
|
||||
<p>If the page does not automatically reload, please click <a href={this.url}>here</a></p>
|
||||
</section>
|
||||
</div>
|
||||
@@ -41,4 +41,4 @@ class PageNotFound extends Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
export default PageNotFound;
|
||||
export default withRouter(PageNotFound);
|
||||
@@ -3,63 +3,64 @@ import Helmet from 'react-helmet';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import ItemUtil, { Item } from './lib/ItemUtil';
|
||||
import ItemType from './item-type';
|
||||
import Loading from '../Loading';
|
||||
import PageNotFound from '../PageNotFound';
|
||||
|
||||
interface Props extends RouteComponentProps<{ id: string, doi: string }> { }
|
||||
|
||||
interface State {
|
||||
id: number;
|
||||
doi: string;
|
||||
loading: boolean;
|
||||
item: Item | null;
|
||||
}
|
||||
|
||||
class DatabaseDetailItem extends Component<Props, State> {
|
||||
|
||||
public state: State = {
|
||||
loading: true,
|
||||
item: null,
|
||||
};
|
||||
|
||||
private id: number;
|
||||
private doi: string;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
const { params } = this.props.match;
|
||||
this.state = {
|
||||
id: typeof params.id !== 'undefined' ? parseInt(params.id, 10) : 0,
|
||||
doi: typeof params.doi !== 'undefined' ? params.doi : '',
|
||||
item: null,
|
||||
}
|
||||
this.id = typeof params.id !== 'undefined' ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : 0) : 0;
|
||||
this.doi = typeof params.doi !== 'undefined' ? params.doi : '';
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
const { params } = nextProps.match;
|
||||
const id = typeof params.id !== 'undefined' ? parseInt(params.id, 10) : 0;
|
||||
const doi = typeof params.doi !== 'undefined' ? params.doi : '';
|
||||
if (doi !== '') {
|
||||
ItemUtil.getByDoi(this.state.doi, (item) => {
|
||||
this.setState({ item });
|
||||
});
|
||||
} else if (id !== 0) {
|
||||
ItemUtil.get(this.state.id, (item) => {
|
||||
this.setState({ item });
|
||||
});
|
||||
}
|
||||
this.setState({ id, doi });
|
||||
this.updateItem(id, doi);
|
||||
this.id = typeof params.id !== 'undefined' ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : 0) : 0;
|
||||
this.doi = typeof params.doi !== 'undefined' ? params.doi : '';
|
||||
this.updateItem();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.updateItem(this.state.id, this.state.doi);
|
||||
this.updateItem();
|
||||
}
|
||||
|
||||
updateItem(id: number, doi: string) {
|
||||
if (doi !== '') {
|
||||
ItemUtil.getByDoi(doi, (item) => {
|
||||
this.setState({ item });
|
||||
updateItem() {
|
||||
if (this.doi !== '') {
|
||||
ItemUtil.getByDoi(this.doi, (item) => {
|
||||
this.setState({ loading: false, item });
|
||||
});
|
||||
} else if (id !== 0) {
|
||||
ItemUtil.get(id, (item) => {
|
||||
this.setState({ item });
|
||||
} else if (this.id !== 0) {
|
||||
ItemUtil.get(this.id, (item) => {
|
||||
this.setState({ loading: false, item });
|
||||
});
|
||||
} else {
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.loading) {
|
||||
return <Loading />;
|
||||
}
|
||||
if (this.state.item === null) {
|
||||
return null;
|
||||
return <PageNotFound />;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import AdvancedSearchQuery from './lib/AdvancedSearchQuery';
|
||||
import ItemUtil, { SortCondition, SearchCallbackFunc } from './lib/ItemUtil';
|
||||
import ItemUtil, { SortCondition } from './lib/ItemUtil';
|
||||
import DatabaseListItem from './lib/DatabaseListItem';
|
||||
|
||||
interface Props extends RouteComponentProps { }
|
||||
@@ -28,9 +28,8 @@ class DatabaseSearchByAdvancedKeyword extends Component<Props, State> {
|
||||
return ItemUtil.getSearchByAdvancedKeywordsUrl(this.state.query);
|
||||
}
|
||||
|
||||
async search(condition: SortCondition, callback: SearchCallbackFunc) {
|
||||
const items = ItemUtil.getListByAdvancedSearchQuery(this.state.query, condition, callback);
|
||||
return items;
|
||||
async search(condition: SortCondition) {
|
||||
return ItemUtil.getListByAdvancedSearchQuery(this.state.query, condition);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -3,9 +3,10 @@ import Helmet from 'react-helmet';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import IndexUtil, { Index, INDEX_ID_PUBLIC } from './lib/IndexUtil';
|
||||
import ItemUtil, { SortCondition, SearchCallbackFunc } from './lib/ItemUtil';
|
||||
import ItemUtil, { SortCondition } from './lib/ItemUtil';
|
||||
import DatabaseListIndex from './lib/DatabaseListIndex';
|
||||
import DatabaseListItem from './lib/DatabaseListItem';
|
||||
import PageNotFound from '../PageNotFound';
|
||||
|
||||
interface Props extends RouteComponentProps<{ id: string }> { }
|
||||
|
||||
@@ -18,18 +19,19 @@ class DatabaseSearchByIndexId extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
const { params } = this.props.match;
|
||||
const indexId = params.id ? parseInt(params.id, 10) : INDEX_ID_PUBLIC;
|
||||
const indexId = params.id ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : null) : INDEX_ID_PUBLIC;
|
||||
this.state = {
|
||||
index: IndexUtil.get(indexId),
|
||||
index: indexId ? IndexUtil.get(indexId) : null,
|
||||
}
|
||||
this.search = this.search.bind(this);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
const { params } = nextProps.match;
|
||||
const indexId = params.id ? parseInt(params.id, 10) : INDEX_ID_PUBLIC;
|
||||
const index = IndexUtil.get(indexId);
|
||||
this.setState({ index });
|
||||
const indexId = params.id ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : null) : INDEX_ID_PUBLIC;
|
||||
this.setState({
|
||||
index: indexId ? IndexUtil.get(indexId) : null,
|
||||
})
|
||||
}
|
||||
|
||||
getUrl() {
|
||||
@@ -39,17 +41,16 @@ class DatabaseSearchByIndexId extends Component<Props, State> {
|
||||
return IndexUtil.getUrl(this.state.index.id);
|
||||
}
|
||||
|
||||
async search(condition: SortCondition, callback: SearchCallbackFunc) {
|
||||
async search(condition: SortCondition) {
|
||||
if (this.state.index === null) {
|
||||
return { total: 0, data: [] };
|
||||
}
|
||||
const items = ItemUtil.getListByIndexId(this.state.index.id, condition, callback);
|
||||
return items;
|
||||
return ItemUtil.getListByIndexId(this.state.index.id, condition);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.index === null) {
|
||||
return null;
|
||||
return <PageNotFound />;
|
||||
}
|
||||
const baseUrl = this.getUrl();
|
||||
const pIndexes = IndexUtil.getParents(this.state.index.id);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import ItemUtil, { SortCondition, SearchCallbackFunc } from './lib/ItemUtil';
|
||||
import ItemUtil, { SortCondition } from './lib/ItemUtil';
|
||||
import DatabaseListItem from './lib/DatabaseListItem';
|
||||
|
||||
interface Props extends RouteComponentProps<{ itemType: string, subItemType: string }> { }
|
||||
@@ -29,12 +29,11 @@ class DatabaseSearchByItemType extends Component<Props, State> {
|
||||
this.setState({ item_type, sub_item_type });
|
||||
}
|
||||
|
||||
async search(condition: SortCondition, callback: SearchCallbackFunc) {
|
||||
async search(condition: SortCondition) {
|
||||
if (this.state.item_type === '') {
|
||||
return { total: 0, data: [] };
|
||||
}
|
||||
const items = ItemUtil.getListByItemType(this.state.item_type, this.state.sub_item_type, condition, callback);
|
||||
return items;
|
||||
return ItemUtil.getListByItemType(this.state.item_type, this.state.sub_item_type, condition);
|
||||
}
|
||||
|
||||
getUrl() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import ItemUtil, { SearchByKeywordType, SortCondition, SearchCallbackFunc } from './lib/ItemUtil';
|
||||
import ItemUtil, { SearchByKeywordType, SortCondition } from './lib/ItemUtil';
|
||||
import DatabaseListItem from './lib/DatabaseListItem';
|
||||
|
||||
interface Props extends RouteComponentProps { }
|
||||
@@ -15,7 +15,7 @@ class DatabaseSearchByKeyword extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
const { type, keyword } = ItemUtil.getSearchKeywordByQuery(this.props.location.search);
|
||||
this.state = {type, keyword};
|
||||
this.state = { type, keyword };
|
||||
this.search = this.search.bind(this);
|
||||
}
|
||||
|
||||
@@ -28,12 +28,11 @@ class DatabaseSearchByKeyword extends Component<Props, State> {
|
||||
return ItemUtil.getSearchByKeywordUrl(this.state.type, this.state.keyword);
|
||||
}
|
||||
|
||||
async search(condition: SortCondition, callback: SearchCallbackFunc) {
|
||||
async search(condition: SortCondition) {
|
||||
if (this.state.keyword === '') {
|
||||
return { total: 0, data: [] };
|
||||
}
|
||||
const items = ItemUtil.getListByKeyword(this.state.type, this.state.keyword, condition, callback);
|
||||
return items;
|
||||
return ItemUtil.getListByKeyword(this.state.type, this.state.keyword, condition);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -2,9 +2,10 @@ import React, { Component, ChangeEvent } from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { Link, withRouter } from 'react-router-dom';
|
||||
import qs from 'query-string';
|
||||
import { Item, SortConditionLimit, SortConditionOrderBy, SortConditionOrderDir, SortCondition, SearchResult, SearchCallbackFunc } from './ItemUtil';
|
||||
import { Item, SortConditionLimit, SortConditionOrderBy, SortConditionOrderDir, SortCondition, SearchResult } from './ItemUtil';
|
||||
import ItemType from '../item-type';
|
||||
import styles from './DatabaseListItem.module.css';
|
||||
import Loading from '../../Loading';
|
||||
|
||||
const SORT_CONDITION_DEFAULT: SortCondition = {
|
||||
limit: 20,
|
||||
@@ -16,7 +17,7 @@ const SORT_CONDITION_RANGE_ORDER_BY = ['title', 'doi', 'last_update_date', 'crea
|
||||
const SORT_CONDITION_RANGE_ORDER_DIR = ['0', '1'];
|
||||
const SORT_CONDITION_RANGE_LIMIT = ['20', '50', '100'];
|
||||
|
||||
export interface SearchFunc { (condition: SortCondition, callback: SearchCallbackFunc): Promise<SearchResult> }
|
||||
export interface SearchFunc { (condition: SortCondition): Promise<SearchResult> }
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
url: string;
|
||||
@@ -24,40 +25,41 @@ interface Props extends RouteComponentProps {
|
||||
}
|
||||
|
||||
interface State {
|
||||
url: string;
|
||||
search: SearchFunc;
|
||||
loading: boolean;
|
||||
condition: SortCondition;
|
||||
result: SearchResult;
|
||||
}
|
||||
|
||||
class DatabaseListItem extends Component<Props, State> {
|
||||
|
||||
private url: string;
|
||||
private search: SearchFunc;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
url: props.url,
|
||||
search: props.search,
|
||||
loading: true,
|
||||
condition: this.getSortConditionByQuery(this.props.location.search),
|
||||
result: { total: 0, data: [] }
|
||||
};
|
||||
this.url = props.url;
|
||||
this.search = props.search;
|
||||
this.handleSelectOrderby = this.handleSelectOrderby.bind(this);
|
||||
this.handleSelectItemcount = this.handleSelectItemcount.bind(this);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
const url = nextProps.url;
|
||||
const search = nextProps.search;
|
||||
async componentWillReceiveProps(nextProps: Props) {
|
||||
this.url = nextProps.url;
|
||||
this.search = nextProps.search;
|
||||
const condition = this.getSortConditionByQuery(nextProps.location.search);
|
||||
this.setState({ url, search, condition });
|
||||
search(condition, (result) => {
|
||||
this.setState({ result });
|
||||
});
|
||||
this.setState({ loading: true });
|
||||
const result = await this.search(condition);
|
||||
this.setState({ loading: false, result, condition });
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.state.search(this.state.condition, (result) => {
|
||||
this.setState({ result });
|
||||
});
|
||||
async componentDidMount() {
|
||||
const result = await this.search(this.state.condition);
|
||||
this.setState({ loading: false, result });
|
||||
}
|
||||
|
||||
handleSelectOrderby(event: ChangeEvent<HTMLSelectElement>) {
|
||||
@@ -85,8 +87,8 @@ class DatabaseListItem extends Component<Props, State> {
|
||||
params.push('order_dir=' + String(newOrderDir));
|
||||
params.push('itemcount=' + String(newLimit));
|
||||
params.push('page=' + String(newPage));
|
||||
const join = this.state.url.indexOf('?') < 0 ? '?' : '&'
|
||||
return (params.length > 0 ? this.state.url + join + params.join('&') : this.state.url);
|
||||
const join = this.url.indexOf('?') < 0 ? '?' : '&'
|
||||
return (params.length > 0 ? this.url + join + params.join('&') : this.url);
|
||||
}
|
||||
|
||||
getDefaultSortCondition() {
|
||||
@@ -183,6 +185,9 @@ class DatabaseListItem extends Component<Props, State> {
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.loading) {
|
||||
return <Loading />;
|
||||
}
|
||||
const result = this.state.result;
|
||||
if (result.data.length === 0) {
|
||||
return (
|
||||
|
||||
@@ -177,8 +177,6 @@ export interface SearchResult {
|
||||
data: Item[];
|
||||
}
|
||||
|
||||
export interface SearchCallbackFunc { (result: SearchResult): void }
|
||||
|
||||
class ItemDatabase {
|
||||
private db: loki;
|
||||
private items: Collection<any> | null = null;
|
||||
@@ -334,7 +332,7 @@ class ItemUtil {
|
||||
return item;
|
||||
}
|
||||
|
||||
static async getListByIndexId(indexId: number, condition: SortCondition, callback: SearchCallbackFunc) {
|
||||
static async getListByIndexId(indexId: number, condition: SortCondition) {
|
||||
const items = await database.getItems();
|
||||
const filter = {
|
||||
'index.index_id': indexId
|
||||
@@ -346,11 +344,10 @@ class ItemUtil {
|
||||
total: result.count(),
|
||||
data: result.sort(itemSorter.sort).offset(offset).limit(condition.limit).data()
|
||||
};
|
||||
callback(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static async getListByItemType(itemType: string, subItemType: string, condition: SortCondition, callback: SearchCallbackFunc) {
|
||||
static async getListByItemType(itemType: string, subItemType: string, condition: SortCondition) {
|
||||
const items = await database.getItems();
|
||||
let filter: any = {
|
||||
item_type_name: 'xnp' + itemType,
|
||||
@@ -377,11 +374,10 @@ class ItemUtil {
|
||||
total: result.count(),
|
||||
data: result.sort(itemSorter.sort).offset(offset).limit(condition.limit).data()
|
||||
};
|
||||
callback(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static async getListByKeyword(type: SearchByKeywordType, keyword: string, condition: SortCondition, callback: SearchCallbackFunc) {
|
||||
static async getListByKeyword(type: SearchByKeywordType, keyword: string, condition: SortCondition) {
|
||||
const items = await database.getItems();
|
||||
const regex = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
const num = keyword.match(/^[0-9]+$/) ? parseInt(keyword, 10) : null;
|
||||
@@ -454,11 +450,10 @@ class ItemUtil {
|
||||
total: result.count(),
|
||||
data: result.sort(itemSorter.sort).offset(offset).limit(condition.limit).data()
|
||||
};
|
||||
callback(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static async getListByAdvancedSearchQuery(query: AdvancedSearchQuery, condition: SortCondition, callback: SearchCallbackFunc) {
|
||||
static async getListByAdvancedSearchQuery(query: AdvancedSearchQuery, condition: SortCondition) {
|
||||
const items = await database.getItems();
|
||||
const filter: any = query.getSearchFilter();
|
||||
const offset = condition.limit * (condition.page - 1);
|
||||
@@ -468,7 +463,6 @@ class ItemUtil {
|
||||
total: result.count(),
|
||||
data: result.sort(itemSorter.sort).offset(offset).limit(condition.limit).data()
|
||||
};
|
||||
callback(ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8372,6 +8372,11 @@ react-side-effect@^1.1.0:
|
||||
exenv "^1.2.1"
|
||||
shallowequal "^1.0.1"
|
||||
|
||||
react-spinner-material@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-spinner-material/-/react-spinner-material-1.1.1.tgz#b996d893251dd82ec12e21e03a28af100df05cab"
|
||||
integrity sha512-zoCsu4hmL2Z6Ihm6aI40+FKUUQ6ckMK2FvAwYpHd9xdc7Q9V4OiDlbDfH5XgxZUZuB/tAjvDaC+dbRexEw2D2A==
|
||||
|
||||
react-transition-group@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.0.1.tgz#8cb8d58763e259da465385bb83b3b41b3ecba629"
|
||||
|
||||
Reference in New Issue
Block a user