diff --git a/lms/static/scripts/frontend_apps/components/dashboard/CourseActivity.tsx b/lms/static/scripts/frontend_apps/components/dashboard/CourseActivity.tsx index a087c97a16..8e7d916f25 100644 --- a/lms/static/scripts/frontend_apps/components/dashboard/CourseActivity.tsx +++ b/lms/static/scripts/frontend_apps/components/dashboard/CourseActivity.tsx @@ -1,12 +1,20 @@ import { Link } from '@hypothesis/frontend-shared'; import { useMemo } from 'preact/hooks'; -import { Link as RouterLink, useParams } from 'wouter-preact'; +import { + Link as RouterLink, + useLocation, + useParams, + useSearch, +} from 'wouter-preact'; import type { AssignmentsResponse, Course } from '../../api-types'; import { useConfig } from '../../config'; -import { urlPath, useAPIFetch } from '../../utils/api'; +import { useAPIFetch } from '../../utils/api'; +import { useDashboardFilters } from '../../utils/dashboard/hooks'; +import { assignmentURL, courseURL } from '../../utils/dashboard/navigation'; import { useDocumentTitle } from '../../utils/hooks'; import { replaceURLParams } from '../../utils/url'; +import DashboardActivityFilters from './DashboardActivityFilters'; import DashboardBreadcrumbs from './DashboardBreadcrumbs'; import FormattedDate from './FormattedDate'; import OrderableActivityTable from './OrderableActivityTable'; @@ -19,13 +27,12 @@ type AssignmentsTableRow = { replies: number; }; -const assignmentURL = (id: number) => urlPath`/assignments/${String(id)}`; - /** * Activity in a list of assignments that are part of a specific course */ export default function CourseActivity() { const { courseId } = useParams<{ courseId: string }>(); + const [, navigate] = useLocation(); const { dashboard } = useConfig(['dashboard']); const { routes } = dashboard; const course = useAPIFetch( @@ -52,6 +59,10 @@ export default function CourseActivity() { const title = course.data?.title ?? 'Untitled course'; useDocumentTitle(title); + const { filters, updateFilters } = useDashboardFilters(); + const { assignmentIds, studentIds } = filters; + const search = useSearch(); + return (
@@ -64,6 +75,34 @@ export default function CourseActivity() { {course.data && title}
+ { + // When no courses are selected (which happens if either "All courses" is + // selected or the active course is deselected), navigate to "All courses" + // section and propagate the rest of the filters. + if (newCourseIds.length === 0) { + navigate(`?${search}`); + } + + // When a course other than the "active" one (the one represented + // in the URL) is selected, navigate to that course and propagate + // the rest of the filters. + const firstDifferentCourse = newCourseIds.find(c => c !== courseId); + if (firstDifferentCourse) { + navigate(`${courseURL(firstDifferentCourse)}?${search}`); + } + }} + selectedAssignmentIds={assignmentIds} + onAssignmentsChange={assignmentIds => updateFilters({ assignmentIds })} + selectedStudentIds={studentIds} + onStudentsChange={studentIds => updateFilters({ studentIds })} + onClearSelection={() => + // Clear every filter but courses + updateFilters({ studentIds: [], assignmentIds: [] }) + } + hasSelection={assignmentIds.length > 0 || studentIds.length > 0} + /> void; onClearSelection?: () => void; + + /** + * Consumers can use this to indicate that there are filters selected. + * If this is not provided, it will be computed based on the presence of + * items in either one of `selectedCourseIds`, `selectedAssignmentIds` or + * `selectedStudentIds`. + */ + hasSelection?: boolean; }; /** @@ -31,11 +39,13 @@ export default function DashboardActivityFilters({ selectedStudentIds, onStudentsChange, onClearSelection, + hasSelection, }: DashboardActivityFiltersProps) { - const hasSelection = - selectedStudentIds.length > 0 || - selectedAssignmentIds.length > 0 || - selectedCourseIds.length > 0; + const hasFiltersSelected = + hasSelection ?? + (selectedStudentIds.length > 0 || + selectedAssignmentIds.length > 0 || + selectedCourseIds.length > 0); const { dashboard } = useConfig(['dashboard']); const { routes } = dashboard; @@ -146,7 +156,7 @@ export default function DashboardActivityFilters({ ))} - {hasSelection && onClearSelection && ( + {hasFiltersSelected && onClearSelection && ( urlPath`/courses/${String(id)}`; - /** * List of courses that belong to a specific organization */ diff --git a/lms/static/scripts/frontend_apps/utils/dashboard/navigation.ts b/lms/static/scripts/frontend_apps/utils/dashboard/navigation.ts new file mode 100644 index 0000000000..30619b24c3 --- /dev/null +++ b/lms/static/scripts/frontend_apps/utils/dashboard/navigation.ts @@ -0,0 +1,9 @@ +import { urlPath } from '../api'; + +export function assignmentURL(id: number) { + return urlPath`/assignments/${String(id)}`; +} + +export function courseURL(id: number | string) { + return urlPath`/courses/${String(id)}`; +}