answer/ui/src/components/QuestionList/index.tsx

193 lines
5.5 KiB
TypeScript
Raw Normal View History

2022-09-27 17:59:05 +08:00
import { FC } from 'react';
2022-10-09 18:20:19 +08:00
import { Row, Col, ListGroup } from 'react-bootstrap';
2022-09-27 17:59:05 +08:00
import { NavLink, useParams, useSearchParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
2022-10-29 20:43:52 +08:00
import { useQuestionList } from '@/services';
import type * as Type from '@answer/common/interface';
2022-09-29 14:56:09 +08:00
import {
Icon,
Tag,
Pagination,
FormatTime,
Empty,
BaseUserCard,
2022-10-09 18:20:19 +08:00
QueryGroup,
2022-09-29 14:56:09 +08:00
} from '@answer/components';
2022-09-27 17:59:05 +08:00
const QuestionOrderKeys: Type.QuestionOrderBy[] = [
'newest',
'active',
'frequent',
'score',
'unanswered',
];
interface Props {
source: 'questions' | 'tag';
}
const QuestionLastUpdate = ({ q }) => {
const { t } = useTranslation('translation', { keyPrefix: 'question' });
if (q.update_time > q.edit_time) {
// question answered
return (
2022-10-14 17:30:16 +08:00
<div className="d-flex">
2022-09-29 14:56:09 +08:00
<BaseUserCard
data={q.last_answered_user_info}
showAvatar={false}
className="me-1"
/>
2022-09-27 17:59:05 +08:00
<FormatTime
time={q.update_time}
className="text-secondary mx-1"
preFix={t('answered')}
/>
2022-10-14 17:30:16 +08:00
</div>
2022-09-27 17:59:05 +08:00
);
}
if (q.edit_time > q.update_time) {
// question modified
return (
2022-10-14 17:30:16 +08:00
<div className="d-flex">
2022-09-29 14:56:09 +08:00
<BaseUserCard
data={q.update_user_info}
showAvatar={false}
className="me-1"
/>
2022-09-27 17:59:05 +08:00
<FormatTime
time={q.edit_time}
className="text-secondary mx-1"
preFix={t('modified')}
/>
2022-10-14 17:30:16 +08:00
</div>
2022-09-27 17:59:05 +08:00
);
}
// default: asked
return (
2022-10-14 17:30:16 +08:00
<div className="d-flex">
2022-09-29 14:56:09 +08:00
<BaseUserCard data={q.user_info} showAvatar={false} className="me-1" />
2022-09-27 17:59:05 +08:00
<FormatTime
time={q.create_time}
preFix={t('asked')}
className="text-secondary mx-1"
/>
2022-10-14 17:30:16 +08:00
</div>
2022-09-27 17:59:05 +08:00
);
};
const QuestionList: FC<Props> = ({ source }) => {
const { t } = useTranslation('translation', { keyPrefix: 'question' });
const { tagName = '' } = useParams();
2022-10-09 18:20:19 +08:00
const [urlSearchParams] = useSearchParams();
2022-09-27 17:59:05 +08:00
const curOrder = urlSearchParams.get('order') || QuestionOrderKeys[0];
const curPage = Number(urlSearchParams.get('page')) || 1;
const pageSize = 20;
const reqParams: Type.QueryQuestionsReq = {
page_size: pageSize,
page: curPage,
order: curOrder as Type.QuestionOrderBy,
tags: [tagName],
};
if (source === 'questions') {
delete reqParams.tags;
}
const { data: listData, isLoading } = useQuestionList(reqParams);
const count = listData?.count || 0;
return (
<div>
<Row className="mb-3">
<Col className="d-flex align-items-center">
<h5 className="fs-5 text-nowrap mb-3 mb-md-0">
{source === 'questions'
? t('all_questions')
: t('x_questions', { count })}
</h5>
</Col>
<Col>
2022-10-09 18:20:19 +08:00
<QueryGroup
data={QuestionOrderKeys}
currentSort={curOrder}
i18nKeyPrefix="question"
2022-10-09 18:20:19 +08:00
/>
2022-09-27 17:59:05 +08:00
</Col>
</Row>
<ListGroup variant="flush" className="border-top border-bottom-0">
{listData?.list?.map((li) => {
return (
2022-10-11 16:18:47 +08:00
<ListGroup.Item
key={li.id}
className="border-bottom pt-3 pb-2 px-0">
2022-09-27 17:59:05 +08:00
<h5 className="text-wrap text-break">
<NavLink to={`/questions/${li.id}`} className="link-dark">
2022-09-27 17:59:05 +08:00
{li.title}
{li.status === 2 ? ` [${t('closed')}]` : ''}
2022-09-27 17:59:05 +08:00
</NavLink>
</h5>
2022-10-14 17:30:16 +08:00
<div className="d-flex flex-column flex-md-row align-items-md-center fs-14 text-secondary">
2022-09-27 17:59:05 +08:00
<QuestionLastUpdate q={li} />
2022-10-14 17:30:16 +08:00
<div className="ms-0 ms-md-3 mt-2 mt-md-0">
<span>
<Icon name="hand-thumbs-up-fill" />
<em className="fst-normal mx-1">{li.vote_count}</em>
</span>
<span
className={`ms-3 ${
li.accepted_answer_id >= 1 ? 'text-success' : ''
}`}>
<Icon
name={
li.accepted_answer_id >= 1
? 'check-circle-fill'
: 'chat-square-text-fill'
}
/>
<em className="fst-normal mx-1">{li.answer_count}</em>
</span>
<span className="summary-stat ms-3">
<Icon name="eye-fill" />
<em className="fst-normal mx-1">{li.view_count}</em>
</span>
</div>
2022-09-27 17:59:05 +08:00
</div>
2022-10-14 17:30:16 +08:00
<div className="question-tags mx-n1 mt-2">
2022-09-27 17:59:05 +08:00
{Array.isArray(li.tags)
? li.tags.map((tag) => {
return (
<Tag
key={tag.slug_name}
2022-10-11 16:18:47 +08:00
className="m-1"
2022-09-27 17:59:05 +08:00
href={`/tags/${
tag.main_tag_slug_name || tag.slug_name
}`}>
{tag.slug_name}
</Tag>
);
})
: null}
</div>
</ListGroup.Item>
);
})}
</ListGroup>
{count <= 0 && !isLoading && <Empty />}
<div className="mt-4 mb-2 d-flex justify-content-center">
<Pagination
currentPage={curPage}
totalSize={count}
pageSize={pageSize}
2022-09-28 15:52:42 +08:00
pathname="/questions"
2022-09-27 17:59:05 +08:00
/>
</div>
</div>
);
};
export default QuestionList;