Coursemology/coursemology2

View on GitHub
client/app/bundles/course/courses/pages/CoursesIndex/index.tsx

Summary

Maintainability
A
3 hrs
Test Coverage
import { FC, ReactElement, useEffect, useState } from 'react';
import { defineMessages } from 'react-intl';
import { useSearchParams } from 'react-router-dom';
import { Button } from '@mui/material';

import AddButton from 'lib/components/core/buttons/AddButton';
import Page from 'lib/components/core/layouts/Page';
import LoadingIndicator from 'lib/components/core/LoadingIndicator';
import { useAppDispatch, useAppSelector } from 'lib/hooks/store';
import toast from 'lib/hooks/toast';
import useTranslation from 'lib/hooks/useTranslation';

import InstanceUserRoleRequestForm from '../../../../system/admin/instance/instance/components/forms/InstanceUserRoleRequestForm';
import CourseDisplay from '../../components/misc/CourseDisplay';
import { fetchCourses } from '../../operations';
import {
  getAllCourseMiniEntities,
  getCourseInstanceUserRoleRequest,
  getCoursePermissions,
} from '../../selectors';
import CoursesNew from '../CoursesNew';

const translations = defineMessages({
  header: {
    id: 'course.courses.CoursesIndex.header',
    defaultMessage: 'Courses',
  },
  newCourse: {
    id: 'course.courses.CoursesIndex.newCourse',
    defaultMessage: 'New Course',
  },
  fetchCoursesFailure: {
    id: 'course.courses.CoursesIndex.fetchCoursesFailure',
    defaultMessage: 'Failed to retrieve courses.',
  },
  newRequest: {
    id: 'course.courses.CoursesIndex.newRequest',
    defaultMessage: 'Request to be an instructor',
  },
  editRequest: {
    id: 'course.courses.CoursesIndex.editRequest',
    defaultMessage: 'Edit your request',
  },
});

const CoursesIndex: FC = () => {
  const { t } = useTranslation();

  const [params] = useSearchParams();

  const [isLoading, setIsLoading] = useState(true);
  const [isRoleRequestDialogOpen, setRoleRequestDialogOpen] = useState(false);
  const courses = useAppSelector(getAllCourseMiniEntities);

  const coursesPermissions = useAppSelector(getCoursePermissions);

  const instanceUserRoleRequest = useAppSelector(
    getCourseInstanceUserRoleRequest,
  );

  const dispatch = useAppDispatch();

  const shouldOpenNewCourseDialog =
    Boolean(params.get('new')) && coursesPermissions?.canCreate;

  const [isNewCourseDialogOpen, setIsNewCourseDialogOpen] = useState(
    shouldOpenNewCourseDialog,
  );

  useEffect(() => {
    dispatch(fetchCourses())
      .finally(() => setIsLoading(false))
      .catch(() => toast.error(t(translations.fetchCoursesFailure)));
  }, [dispatch]);

  useEffect(() => {
    setIsNewCourseDialogOpen(shouldOpenNewCourseDialog);
  }, [shouldOpenNewCourseDialog]);

  // Adding appropriate button to the header
  const headerToolbars: ReactElement[] = [];
  if (coursesPermissions?.canCreate) {
    headerToolbars.push(
      <AddButton onClick={(): void => setIsNewCourseDialogOpen(true)}>
        {t(translations.newCourse)}
      </AddButton>,
    );
  } else if (!isLoading && coursesPermissions?.isCurrentUser) {
    headerToolbars.push(
      <Button
        key="role-request-button"
        color="primary"
        id="role-request-button"
        onClick={(): void => setRoleRequestDialogOpen(true)}
        variant="outlined"
      >
        {instanceUserRoleRequest
          ? t(translations.editRequest)
          : t(translations.newRequest)}
      </Button>,
    );
  }

  return (
    <Page actions={headerToolbars} title={t(translations.header)}>
      {isLoading ? (
        <LoadingIndicator />
      ) : (
        <>
          <CourseDisplay courses={courses} />
          {isNewCourseDialogOpen && (
            <CoursesNew
              onClose={(): void => setIsNewCourseDialogOpen(false)}
              open={isNewCourseDialogOpen}
            />
          )}
          {isRoleRequestDialogOpen && (
            <InstanceUserRoleRequestForm
              instanceUserRoleRequest={instanceUserRoleRequest}
              onClose={(): void => setRoleRequestDialogOpen(false)}
              open={isRoleRequestDialogOpen}
            />
          )}
        </>
      )}
    </Page>
  );
};

const handle = translations.header;

export default Object.assign(CoursesIndex, { handle });