SearchPage.jsx 3.2 KB

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