Coursemology/coursemology2

View on GitHub
client/app/bundles/course/achievement/components/tables/AchievementTable.tsx

Summary

Maintainability
C
1 day
Test Coverage
import { FC, memo } from 'react';
import { defineMessages, FormattedMessage } from 'react-intl';
import { DragIndicator } from '@mui/icons-material';
import { Switch, Typography } from '@mui/material';
import equal from 'fast-deep-equal';
import { TableColumns, TableOptions } from 'types/components/DataTable';
import {
  AchievementMiniEntity,
  AchievementPermissions,
} from 'types/course/achievements';

import { getAchievementBadgeUrl } from 'course/helper/achievements';
import DataTable from 'lib/components/core/layouts/DataTable';
import Link from 'lib/components/core/Link';
import Note from 'lib/components/core/Note';
import { getAchievementURL } from 'lib/helpers/url-builders';
import { getCourseId } from 'lib/helpers/url-helpers';

import AchievementManagementButtons from '../buttons/AchievementManagementButtons';

interface Props {
  achievements: AchievementMiniEntity[];
  permissions: AchievementPermissions | null;
  onTogglePublished: (achievementId: number, data: boolean) => void;
  isReordering: boolean;
}

const translations = defineMessages({
  noAchievement: {
    id: 'course.achievement.AchievementTable.noAchievement',
    defaultMessage: 'No achievement',
  },
});

const styles = {
  badge: {
    maxHeight: 75,
    maxWidth: 75,
  },
  toggle: {},
};

const AchievementTable: FC<Props> = (props) => {
  const { achievements, permissions, onTogglePublished, isReordering } = props;

  if (achievements && achievements.length === 0) {
    return (
      <Note message={<FormattedMessage {...translations.noAchievement} />} />
    );
  }

  const options: TableOptions = {
    download: false,
    filter: false,
    pagination: false,
    print: false,
    search: false,
    selectableRows: 'none',
    setRowProps: (_row, dataIndex, _rowIndex) => {
      const achievementStatus = achievements[dataIndex].achievementStatus;
      let backgroundColor: unknown = null;
      if (achievementStatus === 'granted') {
        backgroundColor = '#dff0d8';
      } else if (
        achievementStatus === 'locked' ||
        !achievements[dataIndex].published
      ) {
        backgroundColor = '#eeeeee';
      }
      return {
        // achievementid is added to the props of every row to allow
        // jquery-ui sortable to identify and extract the achievement id for each row.
        achievementid: `achievement_${achievements[dataIndex].id}`,
        style: { background: backgroundColor },
      };
    },
    // By default, sort displayed achievements by weight
    sortOrder: {
      name: 'weight',
      direction: 'asc',
    },
    viewColumns: false,
  };

  const columns: TableColumns[] = [
    {
      name: 'id',
      label: ' ',
      options: {
        filter: false,
        sort: false,
        customBodyRenderLite: (_) => (isReordering ? <DragIndicator /> : null),
      },
    },
    {
      name: 'weight',
      label: 'weight',
      options: {
        // To enable default weight sorting but column is hidden
        display: false,
        filter: false,
        sort: false,
      },
    },
    {
      name: 'badge',
      label: 'Badge',
      options: {
        filter: false,
        sort: false,
        customBodyRenderLite: (dataIndex): JSX.Element => {
          const badge = achievements[dataIndex].badge;
          const badgeUrl = getAchievementBadgeUrl(
            badge.url,
            achievements[dataIndex].permissions.canDisplayBadge,
          );

          return (
            <img
              key={achievements[dataIndex].id}
              alt={badge.name}
              src={badgeUrl}
              style={styles.badge}
            />
          );
        },
      },
    },
    {
      name: 'title',
      label: 'Title',
      options: {
        filter: false,
        sort: false,
        alignCenter: false,
        customBodyRenderLite: (dataIndex): JSX.Element => {
          const achievement = achievements[dataIndex];

          return (
            <Link
              key={achievement.id}
              to={getAchievementURL(getCourseId(), achievement.id)}
            >
              {achievement.title}
            </Link>
          );
        },
      },
    },
    {
      name: 'description',
      label: 'Description',
      options: {
        filter: false,
        sort: false,
        alignCenter: false,
        hideInSmallScreen: true,
        customBodyRenderLite: (dataIndex): JSX.Element => {
          const achievement = achievements[dataIndex];
          return (
            <Typography
              key={achievements[dataIndex].id}
              dangerouslySetInnerHTML={{ __html: achievement.description }}
              style={{ whiteSpace: 'normal' }}
              variant="body2"
            />
          );
        },
      },
    },
    {
      name: 'conditions',
      label: 'Requirements',
      options: {
        filter: false,
        sort: false,
        hideInSmallScreen: true,
        customBodyRenderLite: (dataIndex): JSX.Element => {
          const conditions = achievements[dataIndex].conditions;
          return (
            <div key={achievements[dataIndex].id}>
              {conditions.map((condition) => (
                <Typography key={condition.id} component="li" variant="body2">
                  {condition.description}
                </Typography>
              ))}
            </div>
          );
        },
      },
    },
  ];

  if (permissions?.canManage) {
    columns.push({
      name: 'published',
      label: 'Published',
      options: {
        filter: false,
        sort: false,
        alignCenter: true,
        hideInSmallScreen: true,
        customBodyRenderLite: (dataIndex): JSX.Element => {
          const achievementId = achievements[dataIndex].id;
          const isPublished = achievements[dataIndex].published;
          return (
            <Switch
              key={achievementId}
              checked={isPublished}
              color="primary"
              onChange={(_, checked): void =>
                onTogglePublished(achievementId, checked)
              }
            />
          );
        },
      },
    });
    columns.push({
      name: 'id',
      label: 'Actions',
      options: {
        filter: false,
        sort: false,
        alignCenter: true,
        customBodyRenderLite: (dataIndex) => {
          const achievement = achievements[dataIndex];
          return (
            <AchievementManagementButtons
              achievement={achievement}
              navigateToIndex={false}
            />
          );
        },
      },
    });
  }

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

export default memo(AchievementTable, equal);