wongjiahau/ttap-web

View on GitHub
src/ts/react/timetableListView.tsx

Summary

Maintainability
B
6 hrs
Test Coverage
import Button from "@material-ui/core/Button";
import IconClock from "@material-ui/icons/Alarm";
import IconGrid from "@material-ui/icons/GridOn";
import IconSave from "@material-ui/icons/Save";
import IconViewList from "@material-ui/icons/ViewList";
import * as React from "react";
import { ObjectStore } from "../dataStructure/objectStore";
import { Key } from "../enums/keyCodeEnum";
import { IGroupedTimetable } from "../model/groupedTimetable";
import { RawSlot } from "../model/rawSlot";
import { ISlotViewModel } from "../model/slotViewModel";
import { CounterView } from "./counterView";
import { StackPanel } from "./panels/stackPanel";
import { NO_OPERATION } from "./setTimeConstraintView";
import { iconStyle } from "./styles";
import { TimetableView } from "./timetableView/timetableView";

export interface ITimetableListViewStateProps {
  currentIndex: number; // non-zero based
  currentSubIndex: number; // nonzero based
  currentTimetable: IGroupedTimetable | null;
  isSummaryOpen: boolean;
  isShowingAlternativeSlotOf: ISlotViewModel | null;
  maxIndex: number; // non-zero based
  slotViewModelStore: ObjectStore<ISlotViewModel>;
}

export interface ITimetableListViewDispatchProps {
  handleGoToNextTimetable: () => void;
  handleGoToPreviousTimetable: () => void;
  handleGoToRandomTimetable: () => void;
  handleGoToNextSubTimetable: () => void;
  handleGoToPreviousSubTimetable: () => void;
  handleOpenSaveTimetableDialog: () => void;
  handleOpenSetTimeConstraintView: () => void;
  handleOpenSlotsTable: () => void;
  handleToggleIsOpenOfSummary: () => void;
  handleSelectSlotChoice: (slotUid: number, newSlotChoice: number) => void;
  handleShowAlternateSlot: (s: ISlotViewModel) => void;
  handleGoToThisAlternateSlot: (
    sourceSlotUid: number,
    destinationSlotUid: number
  ) => void;
}

export interface ITimetableListViewProps
  extends ITimetableListViewStateProps,
    ITimetableListViewDispatchProps {}

export class TimetableListView extends React.Component<
  ITimetableListViewProps,
  {}
> {
  public render() {
    if (!this.props.slotViewModelStore) {
      return Logo();
    }
    const slotsToBeRendered =
      this.props.currentTimetable !== null
        ? this.props.slotViewModelStore.GetBunch(
            this.props.currentTimetable.ListOfSlotUids[
              this.props.currentSubIndex
            ]
          )
        : [];

    const alternativeSlots = this.props.isShowingAlternativeSlotOf
      ? this.props.isShowingAlternativeSlotOf.AlternativeSlots.map(
          ({ slot }) => slot
        )
      : [];

    return (
      <div style={{ display: "grid" }} onKeyDown={this.checkKeys} tabIndex={0}>
        {/* Balloon css */} <link rel="stylesheet" href="balloon.min.css" />
        <div style={{ display: "grid" }}>
          <TimetableView
            slots={slotsToBeRendered}
            alternateSlots={alternativeSlots}
            isShowingAlternativeSlots={alternativeSlots.length > 0}
            isShowingAlternativeSlotOf={this.props.isShowingAlternativeSlotOf}
            stcBoxes={null}
            handleDesetTimeContraintAt={NO_OPERATION}
            handleSetTimeContraintAt={NO_OPERATION}
            isSummaryOpen={this.props.isSummaryOpen}
            handleSelectSlotChoice={this.props.handleSelectSlotChoice}
            handleShowAlternateSlot={this.props.handleShowAlternateSlot}
            handleGoToThisAlternateSlot={this.props.handleGoToThisAlternateSlot}
            handleToggleIsOpenOfSummary={this.props.handleToggleIsOpenOfSummary}
          />
          <div
            style={{
              display: "grid",
              justifyContent: "center",
              gridAutoFlow: "column",
              alignItems: "center",
              gridGap: "8px",
              alignSelf: "start",
              marginBottom: "16px",
            }}
          >
            <Button
              variant="contained"
              color="primary"
              onClick={this.props.handleOpenSetTimeConstraintView}
            >
              <IconClock style={iconStyle} />
              Set time constraint
            </Button>
            <CounterView
              currentIndex={this.props.currentIndex + 1}
              currentSubIndex={this.props.currentSubIndex + 1}
              maxIndex={this.props.maxIndex + 1}
              leftTooltip={"Go to previous timetable (Left arrow)"}
              middleTooltip={"Go to random timetable (R)"}
              rightTooltip={"Go to next timetable (Right arrow)"}
              upTooltip={"Go to previous similar timetable (Up arrow)"}
              downTooltip={"Go to next similar timetable (Down arrow)"}
              handleClickLeft={this.props.handleGoToPreviousTimetable}
              handleClickMiddle={this.props.handleGoToRandomTimetable}
              handleClickRight={this.props.handleGoToNextTimetable}
              handleClickUp={this.props.handleGoToPreviousSubTimetable}
              handleClickDown={this.props.handleGoToNextSubTimetable}
            />
            <Button
              variant="contained"
              color="primary"
              onClick={this.props.handleOpenSaveTimetableDialog}
            >
              <IconSave style={iconStyle} />
              Save
            </Button>
            <Button
              variant="contained"
              color="primary"
              onClick={this.props.handleOpenSlotsTable}
            >
              <IconViewList style={iconStyle} />
              Show slots
            </Button>
          </div>
        </div>
      </div>
    );
  }

  private checkKeys = (e: any) => {
    // refer
    // https://stackoverflow.com/questions/5597060/detecting-arrow-key-presses-in-ja
    // v ascript
    e = e || window.event;
    switch (e.keyCode) {
      case Key.LeftArrow:
        this.props.handleGoToPreviousTimetable();
        break;
      case Key.RightArrow:
        this.props.handleGoToNextTimetable();
        break;
      case Key.DownArrow:
        this.props.handleGoToNextSubTimetable();
        break;
      case Key.UpArrow:
        this.props.handleGoToPreviousSubTimetable();
        break;
      case Key.R:
        this.props.handleGoToRandomTimetable();
        break;
    }
  };
}

function Logo() {
  const gridIconStyle: React.CSSProperties = {
    // width: "50px", height: "50px",
  };
  const stackPanelStyle: React.CSSProperties = {
    position: "absolute",
    right: "1%",
    bottom: "1%",
    // fontSize: "36px"
  };
  return (
    <StackPanel orientation="horizontal" style={stackPanelStyle}>
      <IconGrid style={gridIconStyle} />
      TTAP
    </StackPanel>
  );
}