Coursemology/coursemology2

View on GitHub
client/app/bundles/course/assessment/pages/AssessmentsIndex/AssessmentsTable.tsx

Summary

Maintainability
C
7 hrs
Test Coverage
import {
  AssessmentListData,
  AssessmentsListData,
} from 'types/course/assessment/assessments';

import Link from 'lib/components/core/Link';
import Note from 'lib/components/core/Note';
import PersonalStartEndTime from 'lib/components/extensions/PersonalStartEndTime';
import StackedBadges from 'lib/components/extensions/StackedBadges';
import Table, { ColumnTemplate } from 'lib/components/table';
import useTranslation from 'lib/hooks/useTranslation';

import translations from '../../translations';

import ActionButtons from './ActionButtons';
import StatusBadges from './StatusBadges';

interface AssessmentsTableProps {
  assessments: AssessmentsListData;
}

const AssessmentsTable = (props: AssessmentsTableProps): JSX.Element => {
  const { display, assessments } = props.assessments;
  const { t } = useTranslation();

  const columns: ColumnTemplate<AssessmentListData>[] = [
    {
      of: 'title',
      title: t(translations.title),
      cell: (assessment) => (
        <div className="flex flex-col items-start justify-between xl:flex-row xl:items-center">
          <label className="m-0 font-normal" title={assessment.title}>
            <Link
              className="line-clamp-2 xl:line-clamp-1"
              to={assessment.url}
              underline="hover"
            >
              {assessment.title}
            </Link>
          </label>

          <StatusBadges
            for={assessment}
            isStudent={display.isStudent}
            timelineAlgorithm={display.timelineAlgorithm}
          />
        </div>
      ),
    },
    {
      of: 'baseExp',
      title: t(translations.exp),
      cell: (assessment) => assessment.baseExp ?? '-',
      unless: !display.isGamified,
      className: 'max-md:!hidden text-right',
    },
    {
      of: 'timeBonusExp',
      title: t(translations.bonusExp),
      cell: (assessment) => assessment.timeBonusExp ?? '-',
      unless: !display.bonusAttributes,
      className: 'max-lg:!hidden text-right',
    },
    {
      id: 'conditionals',
      title: t(translations.neededFor),
      cell: (assessment) => (
        <StackedBadges
          badges={assessment.topConditionals}
          remainingCount={assessment.remainingConditionalsCount}
          seeRemainingTooltip={t(translations.seeAllRequirements)}
          seeRemainingUrl={assessment.url}
        />
      ),
      unless: !display.isAchievementsEnabled,
      className: 'max-xl:!hidden whitespace-nowrap',
    },
    {
      of: 'startAt',
      title: t(translations.startsAt),
      cell: (assessment) => (
        <PersonalStartEndTime
          className={
            assessment.isStartTimeBegin
              ? 'text-neutral-400'
              : 'font-bold group-hover?:animate-pulse'
          }
          hideInfo={assessment.status === 'submitted'}
          timeInfo={assessment.startAt}
        />
      ),
      className: 'max-lg:!hidden whitespace-nowrap',
    },
    {
      of: 'bonusEndAt',
      title: t(translations.bonusEndsAt),
      cell: (assessment) => (
        <PersonalStartEndTime
          className={assessment.isBonusEnded ? 'text-neutral-400' : ''}
          hideInfo={assessment.status === 'submitted'}
          timeInfo={assessment.bonusEndAt}
        />
      ),
      unless: !display.bonusAttributes,
      className: 'max-lg:!hidden whitespace-nowrap',
    },
    {
      of: 'endAt',
      title: t(translations.endsAt),
      cell: (assessment) => (
        <PersonalStartEndTime
          className={`${
            display.isStudent &&
            assessment.status !== 'submitted' &&
            assessment.isEndTimePassed
              ? 'text-red-500'
              : ''
          } ${assessment.status === 'submitted' ? 'text-neutral-400' : ''}`}
          hideInfo={assessment.status === 'submitted'}
          timeInfo={assessment.endAt}
        />
      ),
      unless: !display.endTimes,
      className: 'whitespace-nowrap pointer-coarse:max-sm:!hidden',
    },
    {
      id: 'actions',
      title: t(translations.actions),
      className: 'relative',
      cell: (assessment) => (
        <ActionButtons for={assessment} student={display.isStudent} />
      ),
    },
  ];

  if (assessments.length === 0)
    return (
      <Note
        message={
          display.canCreateAssessments
            ? t(translations.createAssessmentToPopulate, {
                category: display.category.title,
              })
            : t(translations.noAssessments)
        }
      />
    );

  return (
    <Table
      className="w-screen border-none sm:w-full"
      columns={columns}
      data={assessments}
      getRowClassName={(assessment): string =>
        `group w-full bg-slot-1 hover?:bg-slot-2 slot-1-white slot-2-neutral-100 ${
          !assessment.isStartTimeBegin ||
          !assessment.conditionSatisfied ||
          assessment.status === 'unavailable'
            ? '!slot-1-neutral-100'
            : ''
        } ${
          assessment.status === 'submitted'
            ? '!slot-1-lime-50 !slot-2-lime-100'
            : ''
        } ${
          assessment.status === 'attempting'
            ? 'shadow-[2px_0_0_0_inset] shadow-amber-500'
            : ''
        }`
      }
      getRowId={(assessment): string => assessment.id.toString()}
    />
  );
};

export default AssessmentsTable;