| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- import React, { useState, useCallback, useRef } from 'react';
- import assert from 'assert';
- import { useTranslation } from 'next-i18next';
- import { useRouter } from 'next/router';
- import { IFocusable } from '~/client/interfaces/focusable';
- import { IPageWithSearchMeta } from '~/interfaces/search';
- import {
- useIsSearchScopeChildrenAsDefault, useIsSearchServiceReachable,
- } from '~/stores/context';
- import { useCurrentPagePath } from '~/stores/page';
- import { useGlobalSearchFormRef } from '~/stores/ui';
- import SearchForm from '../SearchForm';
- import styles from './GlobalSearch.module.scss';
- export type GlobalSearchProps = {
- dropup?: boolean,
- }
- export const GlobalSearch = (props: GlobalSearchProps): JSX.Element => {
- const { t } = useTranslation('commons');
- const { dropup } = props;
- const router = useRouter();
- const globalSearchFormRef = useRef<IFocusable>(null);
- useGlobalSearchFormRef(globalSearchFormRef);
- const { data: isSearchServiceReachable } = useIsSearchServiceReachable();
- const { data: isSearchScopeChildrenAsDefault } = useIsSearchScopeChildrenAsDefault();
- const { data: currentPagePath } = useCurrentPagePath();
- const [text, setText] = useState('');
- const [isScopeChildren, setScopeChildren] = useState<boolean|undefined>(isSearchScopeChildrenAsDefault);
- const [isFocused, setFocused] = useState<boolean>(false);
- const gotoPage = useCallback((data: IPageWithSearchMeta[]) => {
- assert(data.length > 0);
- const page = data[0].data; // should be single page selected
- // navigate to page
- if (page != null) {
- router.push(`/${page._id}`);
- }
- }, [router]);
- const search = useCallback(() => {
- const url = new URL(window.location.href);
- url.pathname = '/_search';
- // construct search query
- let q = text;
- if (isScopeChildren) {
- q += ` prefix:${currentPagePath ?? window.location.pathname}`;
- }
- url.searchParams.append('q', q);
- router.push(url.href);
- }, [currentPagePath, isScopeChildren, router, text]);
- const scopeLabel = isScopeChildren
- ? t('header_search_box.label.This tree')
- : t('header_search_box.label.All pages');
- const isIndicatorShown = !isFocused && (text.length === 0);
- if (isScopeChildren == null || isSearchServiceReachable == null) {
- return <></>;
- }
- return (
- <div className={`grw-global-search ${styles['grw-global-search']} form-group mb-0 d-print-none ${isSearchServiceReachable ? '' : 'has-error'}`}>
- <div className="input-group flex-nowrap">
- <div className={`input-group-prepend ${dropup ? 'dropup' : ''}`}>
- <button
- className="btn btn-secondary dropdown-toggle py-0"
- type="button"
- data-toggle="dropdown"
- aria-haspopup="true"
- data-testid="select-search-scope"
- >
- {scopeLabel}
- </button>
- <div className="dropdown-menu">
- <button
- className="dropdown-item"
- type="button"
- onClick={() => {
- setScopeChildren(false);
- globalSearchFormRef.current?.focus();
- }}
- >
- { t('header_search_box.item_label.All pages') }
- </button>
- <button
- data-tesid="search-current-tree"
- className="dropdown-item"
- type="button"
- onClick={() => {
- setScopeChildren(true);
- globalSearchFormRef.current?.focus();
- }}
- >
- { t('header_search_box.item_label.This tree') }
- </button>
- </div>
- </div>
- <SearchForm
- ref={globalSearchFormRef}
- isSearchServiceReachable={isSearchServiceReachable}
- dropup={dropup}
- onChange={gotoPage}
- onBlur={() => setFocused(false)}
- onFocus={() => setFocused(true)}
- onInputChange={text => setText(text)}
- onSubmit={search}
- />
- { isIndicatorShown && (
- <span className="grw-shortcut-key-indicator">
- <code className="bg-transparent text-muted">/</code>
- </span>
- ) }
- </div>
- </div>
- );
- };
|