radgrad/radgrad2

View on GitHub
archive/ui/component/student/ice/StudentIceColumn.tsx

Summary

Maintainability
A
2 hrs
Test Coverage
import React, { useState } from 'react';
import { Accordion, Icon } from 'semantic-ui-react';
import StudentIceColumnVerified from './StudentIceColumnVerified';
import StudentIceColumnUnverified from './StudentIceColumnUnverified';
import StudentIceColumnRecommended from './StudentIceColumnRecommended';
import { Slugs } from '../../../../../app/imports/api/slug/SlugCollection';
import { Courses } from '../../../../../app/imports/api/course/CourseCollection';
import { Opportunities } from '../../../../../app/imports/api/opportunity/OpportunityCollection';
import { Ice, CourseInstance, ProfileInterest, OpportunityInstance, ICEType } from '../../../../../app/imports/typings/radgrad';

/* Technical Debt
 *   * Improve typing of getCourseSlug:  if typeof course is ICourse else if ... else
 *     type course as ICourse | ICourseInstance
 *
 */

export interface StudentIceColumnProps {
  type: ICEType;
  profileInterests: ProfileInterest[];
  courseInstances: CourseInstance[];
  opportunityInstances: OpportunityInstance[];
  projectedICE: Ice;
  earnedICE: Ice;
}

const StudentIceColumn: React.FC<StudentIceColumnProps> = ({ type, profileInterests, courseInstances, opportunityInstances, projectedICE, earnedICE }) => {
  const [verifiedColumnOpenState, setVerifiedColumnOpen] = useState(true);
  const [unVerifiedColumnOpenState, setUnVerifiedColumnOpen] = useState(false);
  const [recommendedColumnOpenState, setRecommendedColumnOpen] = useState(false);

  const handleVerifiedColumnClick = (e): void => {
    e.preventDefault();
    setVerifiedColumnOpen(!verifiedColumnOpenState);
  };

  const handleUnVerifiedColumnClick = (e): void => {
    e.preventDefault();
    setUnVerifiedColumnOpen(!unVerifiedColumnOpenState);
  };

  const handleRecommendedColumnClick = (e): void => {
    e.preventDefault();
    setRecommendedColumnOpen(!recommendedColumnOpenState);
  };

  // returns the CSS name of a color found in app/public/semantic.min.css depending on the color the widget should be
  const getVerifiedColor = (): string => {
    switch (type) {
      case 'Innovation':
        return 'ice-innovation-color';
      case 'Competency':
        return 'ice-competency-color';
      case 'Experience':
        return 'ice-experience-color';
      default:
        return '';
    }
  };

  // returns the CSS name of a color found in app/public/semantic.min.css depending on the color the widget should be
  // -proj colors are slightly lighter colors of the same shade.
  const getUnverifiedColor = (): string => {
    switch (type) {
      case 'Innovation':
        return 'ice-innovation-proj-color';
      case 'Competency':
        return 'ice-competency-proj-color';
      case 'Experience':
        return 'ice-experience-proj-color';
      default:
        return '';
    }
  };

  const getPoints = (ice: Ice): number => {
    let ret;
    if (type === 'Innovation') {
      ret = ice.i;
    } else if (type === 'Competency') {
      ret = ice.c;
    } else if (type === 'Experience') {
      ret = ice.e;
    }
    return ret;
  };

  const remainingICEPoints = (earned: number, projected: number): number => projected - earned;

  const matchingPoints = (a: number, b: number): boolean => a <= b;

  const icePoints = (ice: Ice): number => {
    let ret;
    if (type === 'Innovation') {
      ret = ice.i;
    } else if (type === 'Competency') {
      ret = ice.c;
    } else if (type === 'Experience') {
      ret = ice.e;
    }
    return ret;
  };

  const getCourseSlug = (course) => {
    if (course.courseID) {
      return Slugs.findDoc(Courses.findDoc(course.courseID).slugID).name;
    }
    return Slugs.findDoc(course.slugID).name;
  };

  const getOpportunitySlug = (opportunity): string => {
    if (opportunity.opportunityID) {
      return Slugs.findDoc(Opportunities.findDoc(opportunity.opportunityID).slugID).name;
    }
    return Slugs.findDoc(opportunity.slugID).name;
  };

  const verifiedColor = getVerifiedColor();
  const unverifiedColor = getUnverifiedColor();

  const earnedICEPoints = getPoints(earnedICE);
  const projectedICEPoints = getPoints(projectedICE);
  const unverifiedICEPoints = remainingICEPoints(earnedICEPoints, projectedICEPoints);

  return (
    <Accordion styled fluid exclusive={false}>
      <Accordion.Title active={verifiedColumnOpenState} onClick={handleVerifiedColumnClick}>
        <Icon name="dropdown" />
        Verified
        <div className={`ui right floated ${verifiedColor}`}>{earnedICEPoints} pts</div>
      </Accordion.Title>
      <Accordion.Content active={verifiedColumnOpenState}>
        <StudentIceColumnVerified
          iceType={type}
          earnedICEPoints={earnedICEPoints}
          getCourseSlug={getCourseSlug}
          matchingPoints={matchingPoints}
          getOpportunitySlug={getOpportunitySlug}
          icePoints={icePoints}
          courseInstances={courseInstances}
          opportunityInstances={opportunityInstances}
        />
      </Accordion.Content>

      <Accordion.Title active={unVerifiedColumnOpenState} onClick={handleUnVerifiedColumnClick}>
        <Icon name="dropdown" />
        Unverified
        <div className={`ui right floated ${unverifiedColor}`}>{unverifiedICEPoints} pts</div>
      </Accordion.Title>
      <Accordion.Content active={unVerifiedColumnOpenState}>
        <StudentIceColumnUnverified
          iceType={type}
          earnedICEPoints={earnedICEPoints}
          icePoints={icePoints}
          projectedICEPoints={projectedICEPoints}
          getCourseSlug={getCourseSlug}
          matchingPoints={matchingPoints}
          getOpportunitySlug={getOpportunitySlug}
          remainingICEPoints={remainingICEPoints}
          courseInstances={courseInstances}
          opportunityInstances={opportunityInstances}
        />
      </Accordion.Content>

      <Accordion.Title active={recommendedColumnOpenState} onClick={handleRecommendedColumnClick}>
        <Icon name="dropdown" />
        Get to 100
      </Accordion.Title>
      <Accordion.Content active={recommendedColumnOpenState}>
        <StudentIceColumnRecommended
          type={type}
          earnedICEPoints={earnedICEPoints}
          getCourseSlug={getCourseSlug}
          projectedICEPoints={projectedICEPoints}
          matchingPoints={matchingPoints}
          icePoints={icePoints}
          getOpportunitySlug={getOpportunitySlug}
          profileInterests={profileInterests}
        />
      </Accordion.Content>
    </Accordion>
  );
};

export default StudentIceColumn;