<commit_before>import * as React from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { Link } from 'react-router-dom';
import { format } from 'date-fns';
import classnames from 'classnames';

import { ModuleCode, ModuleTitle } from 'types/modules';
import { Conflict } from 'types/views';
import config from 'config';
import { renderMCs } from 'utils/modules';
import { conflictToText } from 'utils/planner';
import { AlertTriangle } from 'views/components/icons';
import LinkModuleCodes from 'views/components/LinkModuleCodes';
import { modulePage } from 'views/routes/paths';

import { toSingaporeTime } from 'utils/timify';
import ModuleMenu from './ModuleMenu';
import styles from './PlannerModule.scss';

type Props = Readonly<{
  // Module information
  moduleCode: ModuleCode;
  moduleTitle: ModuleTitle | null;
  moduleCredit: number | null;
  examDate: string | null;
  conflict?: Conflict | null;

  // For draggable
  index: number;

  // Actions
  removeModule: (moduleCode: ModuleCode) => void;
  addCustomData: (moduleCode: ModuleCode) => void;
}>;

/**
 * Component for a single module on the planner
 */
export default class PlannerModule extends React.PureComponent<Props> {
  renderConflict(conflict: Conflict) {
    switch (conflict.type) {
      case 'noInfo':
        return (
          <div className={styles.conflictHeader}>
            <AlertTriangle className={styles.warningIcon} />
            <p>
              No data on this module.{' '}
              <button
                type="button"
                className="btn btn-link btn-inline"
                onClick={this.editCustomData}
              >
                Add data
              </button>
            </p>
          </div>
        );

      case 'semester':
        return (
          <div className={styles.conflictHeader}>
            <AlertTriangle className={styles.warningIcon} />
            <p>
              Module may only only be offered in{' '}
              {conflict.semestersOffered
                .map((semester) => config.shortSemesterNames[semester])
                .join(', ')}
            </p>
          </div>
        );

      case 'exam':
        return (
          <div className={styles.conflictHeader}>
            <AlertTriangle className={styles.warningIcon} />
            <p>{conflict.conflictModules.join(', ')} have clashing exams</p>
          </div>
        );

      case 'prereq':
        return (
          <>
            <div className={styles.conflictHeader}>
              <AlertTriangle className={styles.warningIcon} /><commit_msg>"only only" => "only" (#1991)<commit_after>import * as React from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { Link } from 'react-router-dom';
import { format } from 'date-fns';
import classnames from 'classnames';

import { ModuleCode, ModuleTitle } from 'types/modules';
import { Conflict } from 'types/views';
import config from 'config';
import { renderMCs } from 'utils/modules';
import { conflictToText } from 'utils/planner';
import { AlertTriangle } from 'views/components/icons';
import LinkModuleCodes from 'views/components/LinkModuleCodes';
import { modulePage } from 'views/routes/paths';

import { toSingaporeTime } from 'utils/timify';
import ModuleMenu from './ModuleMenu';
import styles from './PlannerModule.scss';

type Props = Readonly<{
  // Module information
  moduleCode: ModuleCode;
  moduleTitle: ModuleTitle | null;
  moduleCredit: number | null;
  examDate: string | null;
  conflict?: Conflict | null;

  // For draggable
  index: number;

  // Actions
  removeModule: (moduleCode: ModuleCode) => void;
  addCustomData: (moduleCode: ModuleCode) => void;
}>;

/**
 * Component for a single module on the planner
 */
export default class PlannerModule extends React.PureComponent<Props> {
  renderConflict(conflict: Conflict) {
    switch (conflict.type) {
      case 'noInfo':
        return (
          <div className={styles.conflictHeader}>
            <AlertTriangle className={styles.warningIcon} />
            <p>
              No data on this module.{' '}
              <button
                type="button"
                className="btn btn-link btn-inline"
                onClick={this.editCustomData}
              >
                Add data
              </button>
            </p>
          </div>
        );

      case 'semester':
        return (
          <div className={styles.conflictHeader}>
            <AlertTriangle className={styles.warningIcon} />
            <p>
              Module may only be offered in{' '}
              {conflict.semestersOffered
                .map((semester) => config.shortSemesterNames[semester])
                .join(', ')}
            </p>
          </div>
        );

      case 'exam':
        return (
          <div className={styles.conflictHeader}>
            <AlertTriangle className={styles.warningIcon} />
            <p>{conflict.conflictModules.join(', ')} have clashing exams</p>
          </div>
        );

      case 'prereq':
        return (
          <>
            <div className={styles.conflictHeader}>
              <AlertTriangle className={styles.warningIcon} />
{'fraction_non_alphanumeric': 0.1209724098012734, 'fraction_numerical': 0.0007717538105344395, 'mean_word_length': 2.2893401015228427, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 54, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1074255', 'n_tokens_mistral': 1457, 'n_tokens_neox': 1412, 'n_words': 362}