blob: bcc734b21afd2006f1268448c697a756e82da0ed [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Row, Col, ListGroup } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import { useSearchParams } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { usePageTags, useSkeletonControl } from '@/hooks';
import { useCaptchaPlugin } from '@/utils/pluginKit';
import { Pagination } from '@/components';
import { getSearchResult } from '@/services';
import type { SearchParams, SearchRes } from '@/common/interface';
import { logged } from '@/utils/guard';
import {
Head,
SearchHead,
SearchItem,
Tips,
Empty,
ListLoader,
AiCard,
} from './components';
const Index = () => {
const { t } = useTranslation('translation');
const isLogged = logged().ok;
const [searchParams] = useSearchParams();
const page = searchParams.get('page') || 1;
const q = searchParams.get('q') || '';
const order = searchParams.get('order') || 'relevance';
const [isLoading, setIsLoading] = useState(false);
const { isSkeletonShow } = useSkeletonControl(isLoading);
const [data, setData] = useState<SearchRes>({
count: 0,
list: [],
extra: null,
});
const { count = 0, list = [], extra = null } = data || {};
const searchCaptcha = useCaptchaPlugin('search');
const doSearch = () => {
setIsLoading(true);
const params: SearchParams = {
q,
order,
page: Number(page),
size: 20,
};
const captcha = searchCaptcha?.getCaptcha();
if (captcha?.verify) {
params.captcha_id = captcha.captcha_id;
params.captcha_code = captcha.captcha_code;
}
getSearchResult(params)
.then(async (resp) => {
await searchCaptcha?.close();
setData(resp);
})
.catch((err) => {
if (err.isError) {
searchCaptcha?.handleCaptchaError(err.list);
}
})
.finally(() => {
setIsLoading(false);
});
};
useEffect(() => {
if (!searchCaptcha) {
doSearch();
return;
}
searchCaptcha.check(() => {
doSearch();
});
}, [q, order, page]);
let pageTitle = t('search', { keyPrefix: 'page_title' });
if (q) {
pageTitle = `${t('posts_containing', { keyPrefix: 'page_title' })} '${q}'`;
}
usePageTags({
title: pageTitle,
});
return (
<Row className="pt-4 mb-5">
<Col className="page-main flex-auto">
<Head data={extra} />
{isLogged && <AiCard />}
<SearchHead sort={order} count={isLoading ? -1 : count} />
<ListGroup className="rounded-0 mb-5">
{isSkeletonShow ? (
<ListLoader />
) : (
list?.map((item) => {
return <SearchItem key={item.object.id} data={item} />;
})
)}
</ListGroup>
{!isLoading && !list?.length && <Empty />}
<div className="d-flex justify-content-center">
<Pagination
currentPage={Number(page)}
pageSize={20}
totalSize={count}
/>
</div>
</Col>
<Col className="page-right-side mt-4 mt-xl-0">
<Tips />
</Col>
</Row>
);
};
export default Index;