radgrad/radgrad2

View on GitHub
archive/ui/component/advisor/academic-plans/AdvisorAcademicPlanBuilderWidget.tsx

Summary

Maintainability
A
2 hrs
Test Coverage
import React, { useState } from 'react';
import _ from 'lodash';
import { $ } from 'meteor/jquery';
import { Divider, Form, Grid, Header, Icon, Segment } from 'semantic-ui-react';
import { withTracker } from 'meteor/react-meteor-data';
import { AutoForm, SelectField, TextField } from 'uniforms-semantic';
import { SimpleSchema2Bridge } from 'uniforms-bridge-simple-schema-2';
import SimpleSchema from 'simpl-schema';
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
import { RadGradProperties } from '../../../../api/radgrad/RadGradProperties';
import { IPlanChoiceDefine } from '../../../../typings/radgrad';
import { AcademicTerms } from '../../../../api/academic-term/AcademicTermCollection';
import { getDroppableListStyle } from '../../shared/academic-plan/utilities/styles';
import { PlanChoices } from '../../../../api/degree-plan/PlanChoiceCollection';
import AdvisorAPBPlanChoiceWidget from './AdvisorAPBPlanChoiceWidget';
import DraggableCoursePill from '../../shared/academic-plan/DraggableCoursePill';
import { COMBINE_AREA } from './utilities/academic-plan-builder';

interface IAdvisorAcademicPlanBuilderWidgetProps {
  choices: IPlanChoiceDefine[],
  years: number[];
}

const AdvisorAcademicPlanBuilderWidget = (props: IAdvisorAcademicPlanBuilderWidgetProps) => {
  // console.log('AdvisorAcademicPlanBuilderWidget props=%o', props);
  const quarterSystem: boolean = RadGradProperties.getQuarterSystem();
  const initTerms = quarterSystem ? 20 : 15;
  const [choiceList, setChoiceList] = useState([]);
  const initCoursesPerTerm = [];
  for (let i = 0; i < initTerms; i++) {
    initCoursesPerTerm.push(0);
  }
  const [coursesPerTerm, setCoursesPerTerm] = useState(initCoursesPerTerm);

  /**
   * Returns the index into the coursesPerTerm array for the given termLabel
   * @param {string} termLabel the droppableID of the drop target.
   * @returns {number}
   */
  const parseTermYear = (termLabel: string): number => {
    const index = termLabel.indexOf(' ');
    const yearNum = parseInt(termLabel.substring(index), 10);
    const yearIndex = termLabel.indexOf('Year');
    const term = termLabel.substring(0, yearIndex);
    const numTerms = quarterSystem ? 4 : 3;
    let result = 0;
    switch (term) {
      case AcademicTerms.FALL:
        result = 0;
        break;
      case AcademicTerms.WINTER:
        result = 1;
        break;
      case AcademicTerms.SPRING:
        result = quarterSystem ? 2 : 1;
        break;
      default:
        result = quarterSystem ? 3 : 2;
    }
    return result + numTerms * (yearNum - 1);
  };

  const onDragEnd = (result) => {
    // TODO: Check the droppableId to see what kind of drop this is.
    const termIndex = parseTermYear(result.destination.droppableId);
    let courseListIndex = 0;
    for (let i = 0; i < termIndex; i++) {
      courseListIndex += coursesPerTerm[i];
    }
    courseListIndex += result.destination.index;
    choiceList.splice(courseListIndex, 0, result.draggableId);
    coursesPerTerm[termIndex]++;
    // console.log('new state = %o', { courseList, coursesPerTerm });
    setCoursesPerTerm(coursesPerTerm);
    setChoiceList(choiceList);
    const divs = $('#ApbTrash');
    let element = divs;
    while (element && !element.hasClass('segment')) {
      element = element.parent();
    }
  };

  const currentYear = AcademicTerms.getCurrentAcademicTermDoc().year;
  const schema = new SimpleSchema({
    name: String,
    year: { type: SimpleSchema.Integer, allowedValues: props.years, defaultValue: currentYear },
  });
  const formSchema = new SimpleSchema2Bridge(schema);
  const planYears = ['Year 1', 'Year 2', 'Year 3', 'Year 4', 'Year 5'];
  const academicYearStyle = {
    padding: '0 0.6rem',
  };
  let courseListStartIndex = 0;
  let coursesPerTermIndex = 0;
  return (
    <Segment padded>
      <Header dividing>ACADEMIC PLAN</Header>
      <AutoForm schema={formSchema}>
        <Form.Group widths="equal">
          <SelectField name="degree" />
          <TextField name="name" />
          <SelectField name="year" />
        </Form.Group>
      </AutoForm>
      <DragDropContext onDragEnd={onDragEnd}>
        <Grid stackable>
          <Grid.Column width={10}>
            Foo
            <Grid widths="equal">
              <Grid.Row columns="5">
                {_.map(planYears, (py, index) => (
                  <Grid.Column key={index} style={academicYearStyle}>
                    <Divider horizontal>{py}</Divider>
                    <Segment>
                      <Header dividing as="h4">{AcademicTerms.FALL}</Header>
                      <Droppable droppableId={`${AcademicTerms.FALL}${py}`}>
                        {(provided, snapshot) => {
                          const courses = choiceList.slice(courseListStartIndex, courseListStartIndex + coursesPerTerm[coursesPerTermIndex]);
                          courseListStartIndex += coursesPerTerm[coursesPerTermIndex++];
                          // console.log(`${AcademicTerms.FALL}${py}`, courses, courseListStartIndex, coursesPerTermIndex);
                          return (
                            <div
                              ref={provided.innerRef}
                              // style={style}
                              style={getDroppableListStyle(snapshot.isDraggingOver)}
                            >
                              {_.map(courses, (choice, idx) => (
                                <DraggableCoursePill
                                  key={choice}
                                  index={idx}
                                  choice={choice}
                                  draggableId={choice}
                                  satisfied
                                  studentID="fakeID"
                                />
                              ))}
                              {provided.placeholder}
                            </div>
                          );
                        }}
                      </Droppable>
                    </Segment>
                    {
                      quarterSystem ? (
                        <Segment>
                          <Header dividing as="h4">{AcademicTerms.WINTER}</Header>
                          <Droppable droppableId={`${AcademicTerms.WINTER}${py}`}>
                            {(provided, snapshot) => {
                              const courses = choiceList.slice(courseListStartIndex, courseListStartIndex + coursesPerTerm[coursesPerTermIndex]);
                              courseListStartIndex += coursesPerTerm[coursesPerTermIndex++];
                              // console.log(`${AcademicTerms.WINTER}${py}`, courses, courseListStartIndex, coursesPerTermIndex);
                              return (
                                <div
                                  ref={provided.innerRef}
                                  // style={style}
                                  style={getDroppableListStyle(snapshot.isDraggingOver)}
                                >
                                  {_.map(courses, (choice, idx) => (
                                    <DraggableCoursePill
                                      key={choice}
                                      index={idx}
                                      choice={choice}
                                      draggableId={choice}
                                      satisfied
                                      studentID="fakeID"
                                    />
                                  ))}
                                  {provided.placeholder}
                                </div>
                              );
                            }}
                          </Droppable>
                        </Segment>
                        )
                        : ''
                    }
                    <Segment>
                      <Header dividing as="h4">{AcademicTerms.SPRING}</Header>
                      <Droppable droppableId={`${AcademicTerms.SPRING}${py}`}>
                        {(provided, snapshot) => {
                          const courses = choiceList.slice(courseListStartIndex, courseListStartIndex + coursesPerTerm[coursesPerTermIndex]);
                          courseListStartIndex += coursesPerTerm[coursesPerTermIndex++];
                          // console.log(`${AcademicTerms.SPRING}${py}`, courses, courseListStartIndex, coursesPerTermIndex);
                          return (
                            <div
                              ref={provided.innerRef}
                              // style={style}
                              style={getDroppableListStyle(snapshot.isDraggingOver)}
                            >
                              {_.map(courses, (choice, idx) => (
                                <DraggableCoursePill
                                  key={choice}
                                  index={idx}
                                  choice={choice}
                                  draggableId={choice}
                                  satisfied
                                  studentID="fakeID"
                                />
                              ))}
                              {provided.placeholder}
                            </div>
                          );
                        }}
                      </Droppable>
                    </Segment>
                    <Segment>
                      <Header dividing as="h4">{AcademicTerms.SUMMER}</Header>
                      <Droppable droppableId={`${AcademicTerms.SUMMER}${py}`}>
                        {(provided, snapshot) => {
                          const courses = choiceList.slice(courseListStartIndex, courseListStartIndex + coursesPerTerm[coursesPerTermIndex]);
                          courseListStartIndex += coursesPerTerm[coursesPerTermIndex++];
                          // console.log(`${AcademicTerms.SUMMER}${py}`, courses, courseListStartIndex, coursesPerTermIndex);
                          return (
                            <div
                              ref={provided.innerRef}
                              // style={style}
                              style={getDroppableListStyle(snapshot.isDraggingOver)}
                            >
                              {_.map(courses, (choice, idx) => (
                                <DraggableCoursePill
                                  key={choice}
                                  index={idx}
                                  choice={choice}
                                  draggableId={choice}
                                  satisfied
                                  studentID="fakeID"
                                />
                              ))}
                              {provided.placeholder}
                            </div>
                          );
                        }}
                      </Droppable>
                    </Segment>
                  </Grid.Column>
                ))}
              </Grid.Row>
              <Grid.Row>
                <Grid.Column>
                  Bar
                  <Droppable droppableId={COMBINE_AREA}>
                    {(provided, snapshot) => (
                      <div
                        ref={provided.innerRef}
                        // style={style}
                        style={getDroppableListStyle(snapshot.isDraggingOver)}
                      >
                        <Segment>
                          <Icon name="linkify" size="big" />
                          {provided.placeholder}
                        </Segment>
                      </div>
                    )}
                  </Droppable>
                </Grid.Column>
              </Grid.Row>
            </Grid>
          </Grid.Column>
          <Grid.Column width={6}>
            <AdvisorAPBPlanChoiceWidget choices={props.choices} combineChoice="" />
          </Grid.Column>
        </Grid>
      </DragDropContext>
    </Segment>
  );
};

export default withTracker(() => {
  const terms = AcademicTerms.findNonRetired({}, { sort: { year: 1 } });
  const choices = PlanChoices.findNonRetired({}, { sort: { choice: 1 } });
  const years = _.uniq(_.map(terms, (t) => t.year));
  return {
    years,
    choices,
  };
})(AdvisorAcademicPlanBuilderWidget);