SearchPage.jsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // This is the root component for #search-page
  2. import React from 'react';
  3. import PropTypes from 'prop-types';
  4. import { withTranslation } from 'react-i18next';
  5. import { createSubscribedElement } from './UnstatedUtils';
  6. import AppContainer from '../services/AppContainer';
  7. import { toastError } from '../util/apiNotification';
  8. import SearchPageForm from './SearchPage/SearchPageForm';
  9. import SearchResult from './SearchPage/SearchResult';
  10. class SearchPage extends React.Component {
  11. constructor(props) {
  12. super(props);
  13. this.state = {
  14. searchingKeyword: decodeURI(this.props.query.q) || '',
  15. searchedKeyword: '',
  16. searchedPages: [],
  17. searchResultMeta: {},
  18. };
  19. this.search = this.search.bind(this);
  20. this.changeURL = this.changeURL.bind(this);
  21. }
  22. componentDidMount() {
  23. const keyword = this.state.searchingKeyword;
  24. if (keyword !== '') {
  25. this.search({ keyword });
  26. }
  27. }
  28. static getQueryByLocation(location) {
  29. const search = location.search || '';
  30. const query = {};
  31. search.replace(/^\?/, '').split('&').forEach((element) => {
  32. const queryParts = element.split('=');
  33. query[queryParts[0]] = decodeURIComponent(queryParts[1]).replace(/\+/g, ' ');
  34. });
  35. return query;
  36. }
  37. changeURL(keyword, refreshHash) {
  38. let hash = window.location.hash || '';
  39. // TODO 整理する
  40. if (refreshHash || this.state.searchedKeyword !== '') {
  41. hash = '';
  42. }
  43. if (window.history && window.history.pushState) {
  44. window.history.pushState('', `Search - ${keyword}`, `/_search?q=${keyword}${hash}`);
  45. }
  46. }
  47. search(data) {
  48. const keyword = data.keyword;
  49. if (keyword === '') {
  50. this.setState({
  51. searchingKeyword: '',
  52. searchedPages: [],
  53. searchResultMeta: {},
  54. });
  55. return true;
  56. }
  57. this.setState({
  58. searchingKeyword: keyword,
  59. });
  60. this.props.appContainer.apiGet('/search', { q: keyword })
  61. .then((res) => {
  62. this.changeURL(keyword);
  63. this.setState({
  64. searchedKeyword: keyword,
  65. searchedPages: res.data,
  66. searchResultMeta: res.meta,
  67. });
  68. })
  69. .catch((err) => {
  70. toastError(err);
  71. });
  72. }
  73. render() {
  74. return (
  75. <div>
  76. <div className="search-page-input sps sps--abv">
  77. <SearchPageForm
  78. t={this.props.t}
  79. onSearchFormChanged={this.search}
  80. keyword={this.state.searchingKeyword}
  81. />
  82. </div>
  83. <SearchResult
  84. pages={this.state.searchedPages}
  85. searchingKeyword={this.state.searchingKeyword}
  86. searchResultMeta={this.state.searchResultMeta}
  87. />
  88. </div>
  89. );
  90. }
  91. }
  92. /**
  93. * Wrapper component for using unstated
  94. */
  95. const SearchPageWrapper = (props) => {
  96. return createSubscribedElement(SearchPage, props, [AppContainer]);
  97. };
  98. SearchPage.propTypes = {
  99. t: PropTypes.func.isRequired, // i18next
  100. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  101. query: PropTypes.object,
  102. };
  103. SearchPage.defaultProps = {
  104. // pollInterval: 1000,
  105. query: SearchPage.getQueryByLocation(window.location || {}),
  106. };
  107. export default withTranslation()(SearchPageWrapper);