Coursemology/coursemology2

View on GitHub
client/app/bundles/course/forum/components/tables/ForumTable.tsx

Summary

Maintainability
C
1 day
Test Coverage
import { FC, memo } from 'react';
import { defineMessages } from 'react-intl';
import Email from '@mui/icons-material/Email';
import Help from '@mui/icons-material/Help';
import { Tooltip, Typography } from '@mui/material';
import equal from 'fast-deep-equal';
import { TableColumns, TableOptions } from 'types/components/DataTable';
import { ForumEntity } from 'types/course/forums';

import DataTable from 'lib/components/core/layouts/DataTable';
import Link from 'lib/components/core/Link';
import Note from 'lib/components/core/Note';
import CustomBadge from 'lib/components/extensions/CustomBadge';
import useTranslation from 'lib/hooks/useTranslation';

import ForumManagementButtons from '../buttons/ForumManagementButtons';
import SubscribeButton from '../buttons/SubscribeButton';

interface Props {
  forums: ForumEntity[];
}

const translations = defineMessages({
  noForum: {
    id: 'course.forum.ForumTable.noForum',
    defaultMessage: 'No Forum',
  },
  hasUnresolved: {
    id: 'course.forum.ForumTable.hasUnresolved',
    defaultMessage: 'Has unresolved question(s)',
  },
  forum: {
    id: 'course.forum.ForumTable.forum',
    defaultMessage: 'Forum',
  },
  topics: {
    id: 'course.forum.ForumTable.topics',
    defaultMessage: 'Topics',
  },
  votes: {
    id: 'course.forum.ForumTable.votes',
    defaultMessage: 'Votes',
  },
  posts: {
    id: 'course.forum.ForumTable.posts',
    defaultMessage: 'Posts',
  },
  views: {
    id: 'course.forum.ForumTable.views',
    defaultMessage: 'Views',
  },
  isSubscribed: {
    id: 'course.forum.ForumTable.isSubscribed',
    defaultMessage: 'Subscribed?',
  },
  autoSubscribe: {
    id: 'course.forum.ForumTable.autoSubscribe',
    defaultMessage:
      'Users will be automatically subscribed to a topic in this forum when they create a post in the topic.',
  },
});

const ForumTable: FC<Props> = (props) => {
  const { forums } = props;
  const { t } = useTranslation();
  if (forums && forums.length === 0) {
    return <Note message={t(translations.noForum)} />;
  }

  const options: TableOptions = {
    download: false,
    filter: false,
    pagination: false,
    print: false,
    rowHover: false,
    search: false,
    selectableRows: 'none',
    setRowProps: (_row, dataIndex, _rowIndex) => {
      const forum = forums[dataIndex];
      return {
        className: `forum_${forum.id} relative hover:bg-neutral-100`,
      };
    },
    viewColumns: false,
  };

  const columns: TableColumns[] = [
    {
      name: 'name',
      label: t(translations.forum),
      options: {
        filter: false,
        sort: true,
        alignCenter: false,
        customBodyRenderLite: (dataIndex): JSX.Element => {
          const forum = forums[dataIndex];

          return (
            <>
              {/* Abstract the following */}
              <div className="flex flex-col items-start justify-between xl:flex-row xl:items-center">
                <label
                  className="m-0 flex flex-row space-x-4 font-normal"
                  title={forum.name}
                >
                  <Link
                    key={forum.id}
                    // TODO: Change to lg:line-clamp-1 once the current sidebar is gone
                    className="line-clamp-2 xl:line-clamp-1"
                    to={forum.forumUrl}
                  >
                    {forum.name}
                  </Link>
                  <CustomBadge
                    badgeContent={forum.topicUnreadCount}
                    color="info"
                  />
                </label>
                <div className="flex items-center space-x-2 max-xl:mt-2 xl:ml-2">
                  {forum.isUnresolved && (
                    <Tooltip
                      disableInteractive
                      title={t(translations.hasUnresolved)}
                    >
                      <Help className="text-3xl text-yellow-500 hover?:text-yellow-600" />
                    </Tooltip>
                  )}
                  {forum.forumTopicsAutoSubscribe && (
                    <Tooltip
                      disableInteractive
                      title={t(translations.autoSubscribe)}
                    >
                      <Email className="text-3xl text-neutral-500 hover?:text-neutral-600" />
                    </Tooltip>
                  )}
                </div>
              </div>
              <Typography
                className="whitespace-normal"
                dangerouslySetInnerHTML={{
                  __html: forum.description,
                }}
                variant="body2"
              />
            </>
          );
        },
      },
    },
    {
      name: 'topicCount',
      label: t(translations.topics),
      options: {
        filter: false,
        sort: true,
        hideInSmallScreen: true,
      },
    },
    {
      name: 'topicPostCount',
      label: t(translations.posts),
      options: {
        filter: false,
        sort: true,
        hideInSmallScreen: true,
      },
    },
    {
      name: 'topicViewCount',
      label: t(translations.views),
      options: {
        filter: false,
        sort: true,
        hideInSmallScreen: true,
      },
    },
    {
      name: 'subscribed',
      label: t(translations.isSubscribed),
      options: {
        filter: false,
        sort: false,
        alignCenter: true,
        customBodyRenderLite: (dataIndex): JSX.Element => {
          const forum = forums[dataIndex];
          return (
            <SubscribeButton
              emailSubscription={forum.emailSubscription}
              entityId={forum.id}
              entityTitle={forum.name}
              entityType="forum"
              entityUrl={forum.forumUrl}
              type="checkbox"
            />
          );
        },
      },
    },
    {
      name: 'id',
      label: ' ',
      options: {
        filter: false,
        sort: false,
        alignCenter: true,
        customBodyRenderLite: (dataIndex): JSX.Element => {
          return (
            <ForumManagementButtons
              forum={forums[dataIndex]}
              showOnHover={
                forums[dataIndex].permissions.canEditForum ||
                forums[dataIndex].permissions.canDeleteForum
              }
            />
          );
        },
      },
    },
  ];

  return (
    <DataTable columns={columns} data={forums} options={options} withMargin />
  );
};

export default memo(ForumTable, (prevProps, nextProps) => {
  return equal(prevProps.forums, nextProps.forums);
});