122 lines
3.8 KiB
JavaScript
122 lines
3.8 KiB
JavaScript
import React, { useContext, useEffect } from 'react';
|
|
|
|
import classNames from 'classnames';
|
|
import isEmpty from 'lodash/isEmpty';
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
|
|
import { Spinner } from '@edx/paragon';
|
|
|
|
import SearchInfo from '../../components/SearchInfo';
|
|
import { RequestStatus } from '../../data/constants';
|
|
import { DiscussionContext } from '../common/context';
|
|
import { selectAreThreadsFiltered, selectDiscussionProvider } from '../data/selectors';
|
|
import { clearFilter, clearSort } from '../posts/data/slices';
|
|
import NoResults from '../posts/NoResults';
|
|
import { handleKeyDown } from '../utils';
|
|
import {
|
|
selectArchivedTopics, selectCoursewareTopics, selectFilteredTopics, selectLoadingStatus,
|
|
selectNonCoursewareTopics, selectTopicFilter, selectTopics,
|
|
} from './data/selectors';
|
|
import { setFilter } from './data/slices';
|
|
import { fetchCourseTopicsV3 } from './data/thunks';
|
|
import { ArchivedBaseGroup, SectionBaseGroup, Topic } from './topic';
|
|
|
|
function TopicsList() {
|
|
const loadingStatus = useSelector(selectLoadingStatus);
|
|
const coursewareTopics = useSelector(selectCoursewareTopics);
|
|
const nonCoursewareTopics = useSelector(selectNonCoursewareTopics);
|
|
const archivedTopics = useSelector(selectArchivedTopics);
|
|
|
|
return (
|
|
<>
|
|
{nonCoursewareTopics?.map((topic, index) => (
|
|
<Topic
|
|
key={topic.id}
|
|
topic={topic}
|
|
showDivider={(nonCoursewareTopics.length - 1) !== index}
|
|
/>
|
|
))}
|
|
{coursewareTopics?.map((topic, index) => (
|
|
<SectionBaseGroup
|
|
key={topic.id}
|
|
section={topic?.children}
|
|
sectionId={topic.id}
|
|
sectionTitle={topic.displayName}
|
|
showDivider={(coursewareTopics.length - 1) !== index}
|
|
/>
|
|
))}
|
|
{!isEmpty(archivedTopics) && (
|
|
<ArchivedBaseGroup
|
|
archivedTopics={archivedTopics}
|
|
showDivider={(!isEmpty(nonCoursewareTopics) || !isEmpty(coursewareTopics))}
|
|
/>
|
|
)}
|
|
{loadingStatus === RequestStatus.IN_PROGRESS && (
|
|
<div className="d-flex justify-content-center p-4">
|
|
<Spinner animation="border" variant="primary" size="lg" />
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
function TopicsView() {
|
|
const dispatch = useDispatch();
|
|
const { courseId } = useContext(DiscussionContext);
|
|
const provider = useSelector(selectDiscussionProvider);
|
|
const topicFilter = useSelector(selectTopicFilter);
|
|
const filteredTopics = useSelector(selectFilteredTopics);
|
|
const loadingStatus = useSelector(selectLoadingStatus);
|
|
const isPostsFiltered = useSelector(selectAreThreadsFiltered);
|
|
const topics = useSelector(selectTopics);
|
|
|
|
useEffect(() => {
|
|
if (provider) {
|
|
dispatch(fetchCourseTopicsV3(courseId));
|
|
}
|
|
}, [provider]);
|
|
|
|
useEffect(() => {
|
|
if (isPostsFiltered) {
|
|
dispatch(clearFilter());
|
|
dispatch(clearSort());
|
|
}
|
|
}, [isPostsFiltered]);
|
|
|
|
return (
|
|
<div className="d-flex flex-column h-100" data-testid="inContext-topics-view">
|
|
{topicFilter && (
|
|
<>
|
|
<SearchInfo
|
|
text={topicFilter}
|
|
count={filteredTopics.length}
|
|
loadingStatus={loadingStatus}
|
|
onClear={() => dispatch(setFilter(''))}
|
|
/>
|
|
{filteredTopics.length === 0 && loadingStatus === RequestStatus.SUCCESSFUL && <NoResults />}
|
|
</>
|
|
)}
|
|
<div
|
|
className={classNames('list-group list-group-flush flex-fill', {
|
|
'justify-content-center': loadingStatus === RequestStatus.IN_PROGRESS && isEmpty(topics),
|
|
})}
|
|
role="list"
|
|
onKeyDown={e => handleKeyDown(e)}
|
|
>
|
|
{topicFilter ? (
|
|
filteredTopics?.map((topic) => (
|
|
<Topic
|
|
key={topic.id}
|
|
topic={topic}
|
|
/>
|
|
))
|
|
) : (
|
|
<TopicsList />
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default TopicsView;
|