Compare commits
1 Commits
bw/hackath
...
schen/cour
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0834baee05 |
@@ -420,3 +420,10 @@ export async function unsubscribeFromCourseGoal(token) {
|
||||
return getAuthenticatedHttpClient().post(url.href)
|
||||
.then(res => camelCaseObject(res));
|
||||
}
|
||||
|
||||
export async function searchCourseContentFromAPI(courseId, searchKeyword) {
|
||||
const url = new URL(`${getConfig().LMS_BASE_URL}/search/${courseId}`);
|
||||
const formData = `search_string=${searchKeyword}&page_size=20&page_index=0`;
|
||||
return getAuthenticatedHttpClient().post(url.href, formData)
|
||||
.then(res => camelCaseObject(res));
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
postDismissWelcomeMessage,
|
||||
postRequestCert,
|
||||
getLiveTabIframe,
|
||||
searchCourseContentFromAPI,
|
||||
} from './api';
|
||||
|
||||
import {
|
||||
@@ -139,3 +140,18 @@ export function processEvent(eventData, getTabData) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function searchCourseContent(courseId, searchKeyword) {
|
||||
return async (dispatch) => {
|
||||
searchCourseContentFromAPI(courseId, searchKeyword).then(response => {
|
||||
const { data } = response;
|
||||
dispatch(addModel({
|
||||
modelType: 'contentSearchResults',
|
||||
model: {
|
||||
id: courseId,
|
||||
...data,
|
||||
},
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import { useModel } from '../../generic/model-store';
|
||||
import WelcomeMessage from './widgets/WelcomeMessage';
|
||||
import ProctoringInfoPanel from './widgets/ProctoringInfoPanel';
|
||||
import AccountActivationAlert from '../../alerts/logistration-alert/AccountActivationAlert';
|
||||
import CoursewareSearch from './widgets/CoursewareSearch';
|
||||
|
||||
const OutlineTab = ({ intl }) => {
|
||||
const {
|
||||
@@ -157,6 +158,7 @@ const OutlineTab = ({ intl }) => {
|
||||
)}
|
||||
<StartOrResumeCourseCard />
|
||||
<WelcomeMessage courseId={courseId} />
|
||||
<CoursewareSearch courseId={courseId} />
|
||||
{rootCourseId && (
|
||||
<>
|
||||
<div className="row w-100 m-0 mb-3 justify-content-end">
|
||||
|
||||
@@ -331,6 +331,16 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Onboarding Past Due',
|
||||
description: 'Text that show when the deadline of proctortrack onboarding exam has passed, it appears on button that start the onboarding exam however for this case the button is disabled for obvious reason',
|
||||
},
|
||||
coursewareSearchInputLabel: {
|
||||
id: 'learning.coursewareSearch.inputLabel',
|
||||
defaultMessage: 'Course Content Search',
|
||||
description: 'Search input label',
|
||||
},
|
||||
coursewareSearchButtonLabel: {
|
||||
id: 'learning.coursewareSearch.buttonLabel',
|
||||
defaultMessage: 'Search',
|
||||
description: 'Search button label',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
|
||||
109
src/course-home/outline-tab/widgets/CoursewareSearch.jsx
Normal file
109
src/course-home/outline-tab/widgets/CoursewareSearch.jsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
Container,
|
||||
Hyperlink,
|
||||
Layout,
|
||||
} from '@edx/paragon';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { sendTrackingLogEvent } from '@edx/frontend-platform/analytics';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import messages from '../messages';
|
||||
import { useModel, updateModel } from '../../../generic/model-store';
|
||||
import { searchCourseContent } from '../../data/thunks';
|
||||
|
||||
const CoursewareSearch = ({ courseId, intl }) => {
|
||||
const {
|
||||
org,
|
||||
} = useModel('courseHomeMeta', courseId);
|
||||
|
||||
const eventProperties = {
|
||||
org_key: org,
|
||||
courserun_key: courseId,
|
||||
};
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const {
|
||||
results,
|
||||
took,
|
||||
} = useModel('contentSearchResults', courseId);
|
||||
|
||||
const [searchKeyword, setSearchKeyword] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (!searchKeyword) {
|
||||
dispatch(updateModel({
|
||||
modelType: 'contentSearchResults',
|
||||
model: {
|
||||
id: courseId,
|
||||
results: [],
|
||||
took: false,
|
||||
},
|
||||
}));
|
||||
}
|
||||
}, [searchKeyword]);
|
||||
|
||||
const searchClick = () => {
|
||||
sendTrackingLogEvent('edx.course.home.courseware_search.clicked', {
|
||||
...eventProperties,
|
||||
event_type: 'search',
|
||||
keyword: searchKeyword,
|
||||
});
|
||||
dispatch(searchCourseContent(courseId, searchKeyword));
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form.Group>
|
||||
<Form.Control
|
||||
className="float-left w-75"
|
||||
floatingLabel={intl.formatMessage(messages.coursewareSearchInputLabel)}
|
||||
value={searchKeyword}
|
||||
onChange={(e) => setSearchKeyword(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
variant="primary"
|
||||
className="float-left"
|
||||
onClick={() => searchClick()}
|
||||
>
|
||||
{intl.formatMessage(messages.coursewareSearchButtonLabel)}
|
||||
</Button>
|
||||
<div className="clearfix" />
|
||||
</Form.Group>
|
||||
{(took && results.length === 0) && (
|
||||
<Container size="xl">
|
||||
{
|
||||
`Could not find any component matching "${searchKeyword}"`
|
||||
}
|
||||
</Container>
|
||||
)}
|
||||
{(took && results.length > 0) && results.map(resultItem => (
|
||||
<Container
|
||||
size="xl"
|
||||
>
|
||||
<Layout>
|
||||
<Layout.Element>
|
||||
<Hyperlink
|
||||
destination={`${getConfig().LMS_BASE_URL}${resultItem.data.url}`}
|
||||
>
|
||||
{ resultItem.data.location.join('/') }
|
||||
</Hyperlink>
|
||||
</Layout.Element>
|
||||
</Layout>
|
||||
</Container>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
CoursewareSearch.propTypes = {
|
||||
courseId: PropTypes.string.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(CoursewareSearch);
|
||||
Reference in New Issue
Block a user