<commit_before>import React from 'react';
import _ from 'lodash';
import {sortByGrade} from '../helpers/SortHelpers';
import {
  fetchGradeLevelsJson,
  fetchStudentsJson,
  postClassroomsForGrade
} from './api';
import {initialStudentIdsByRoom, areAllStudentsPlaced} from './studentIdsByRoomFunctions';
import ClassroomListCreatorWorkflow from './ClassroomListCreatorWorkflow';
import uuidv4 from 'uuid/v4';

export const STEPS = [
  'Choose your grade',
  'Make a plan',
  'Create your classrooms',
  'Notes to principal',
  'Submit to principal'
];

// Entry point for grade-level teaching teams to create classroom lists.
// This component manages state transitions and hands off requests to the server
// and rendering to other components.  On state changes, it saves to the server
// with some throttling to prevent too much server communication.
export default class ClassroomListCreatorPage extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      balanceId: props.balanceId || uuidv4(),
      stepIndex: 0,

      // first
      schools: null, // from server
      gradeLevelsNextYear: null, // from server
      schoolId: null,
      gradeLevelNextYear: null,

      // second
      educatorNames: null, // from server
      students: null, // from server
      classroomsCount: 4,
      educators: [],
      planText: '',

      // third
      studentIdsByRoom: null,

      // fourth
      principalNoteText: ''
    };

    this.doSaveChanges = _.throttle(this.doSaveChanges, 5000);
    this.fetchGradeLevels = this.fetchGradeLevels.bind(this);
    this.fetchStudents = this.fetchStudents.bind(this);
    this.onFetchedGradeLevels = this.onFetchedGradeLevels.bind(this);
    this.onFetchedStudents = this.onFetchedStudents.bind(this);
    this.onStepChanged = this.onStepChanged.bind(this);
    this.onSchoolIdChanged = this.onSchoolIdChanged.bind(this);
    this.onGradeLevelNextYearChanged = this.onGradeLevelNextYearChanged.bind(this);
    this.onClassroomsCountIncremented = this.onClassroomsCountIncremented.bind(this);
    this.onPlanTextChanged = this.onPlanTextChanged.bind(this);
    this.onEducatorsChanged = this.onEducatorsChanged.bind(this);
    this.onClassroomListsChanged = this.onClassroomListsChanged.bind(this);
    this.onPrincipalNoteChanged = this.onPrincipalNoteChanged.bind(this);
  }

  componentDidMount() {
    this.doSizePage();
    this.doReplaceState();
    window.addEventListener('beforeunload', this.onBeforeUnload);
    this.triggerFetches();
  }

  componentDidUpdate() {
    this.doSaveChanges();
    this.triggerFetches();
  }

  componentWillUnmount() {
    if (this.doSaveChanges.flush) this.doSaveChanges.flush(); // flush any queued changes
    window.removeEventListener('beforeunload', this.onBeforeUnload);
  }

  doSizePage() {
    window.document.body.style['min-width'] = '1000px';
  }
  
  doReplaceState() {
    const {balanceId} = this.state;
    const path = `/balancing/${balanceId}`;
    if (!this.props.disableHistory) {
      window.history.replaceState({}, null, path);
    }
  }

  // This method is throttled.
  doSaveChanges() {
    const {
      balanceId,
      stepIndex,
      schoolId,
      gradeLevelNextYear,
      educators,
      classroomsCount,
      planText,
      studentIdsByRoom,
      principalNotesText
    } = this.state;
    if (balanceId === null) return;

    const payload = {
      balanceId,
      stepIndex,
      schoolId,
      gradeLevelNextYear,
      educators,
      classroomsCount,
      planText,
      studentIdsByRoom,
      principalNotesText,
      clientNowMs: moment.utc().unix()
    };
    postClassroomsForGrade(payload);<commit_msg>Delay initial saving until school and grade are picked"<commit_after>import React from 'react';
import _ from 'lodash';
import {sortByGrade} from '../helpers/SortHelpers';
import {
  fetchGradeLevelsJson,
  fetchStudentsJson,
  postClassroomsForGrade
} from './api';
import {initialStudentIdsByRoom, areAllStudentsPlaced} from './studentIdsByRoomFunctions';
import ClassroomListCreatorWorkflow from './ClassroomListCreatorWorkflow';
import uuidv4 from 'uuid/v4';

export const STEPS = [
  'Choose your grade',
  'Make a plan',
  'Create your classrooms',
  'Notes to principal',
  'Submit to principal'
];

// Entry point for grade-level teaching teams to create classroom lists.
// This component manages state transitions and hands off requests to the server
// and rendering to other components.  On state changes, it saves to the server
// with some throttling to prevent too much server communication.
export default class ClassroomListCreatorPage extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      balanceId: props.balanceId || uuidv4(),
      stepIndex: 0,

      // first
      schools: null, // from server
      gradeLevelsNextYear: null, // from server
      schoolId: null,
      gradeLevelNextYear: null,

      // second
      educatorNames: null, // from server
      students: null, // from server
      classroomsCount: 4,
      educators: [],
      planText: '',

      // third
      studentIdsByRoom: null,

      // fourth
      principalNoteText: ''
    };

    this.doSaveChanges = _.throttle(this.doSaveChanges, 5000);
    this.fetchGradeLevels = this.fetchGradeLevels.bind(this);
    this.fetchStudents = this.fetchStudents.bind(this);
    this.onFetchedGradeLevels = this.onFetchedGradeLevels.bind(this);
    this.onFetchedStudents = this.onFetchedStudents.bind(this);
    this.onStepChanged = this.onStepChanged.bind(this);
    this.onSchoolIdChanged = this.onSchoolIdChanged.bind(this);
    this.onGradeLevelNextYearChanged = this.onGradeLevelNextYearChanged.bind(this);
    this.onClassroomsCountIncremented = this.onClassroomsCountIncremented.bind(this);
    this.onPlanTextChanged = this.onPlanTextChanged.bind(this);
    this.onEducatorsChanged = this.onEducatorsChanged.bind(this);
    this.onClassroomListsChanged = this.onClassroomListsChanged.bind(this);
    this.onPrincipalNoteChanged = this.onPrincipalNoteChanged.bind(this);
  }

  componentDidMount() {
    this.doSizePage();
    this.doReplaceState();
    window.addEventListener('beforeunload', this.onBeforeUnload);
    this.triggerFetches();
  }

  componentDidUpdate() {
    this.doSaveChanges();
    this.triggerFetches();
  }

  componentWillUnmount() {
    if (this.doSaveChanges.flush) this.doSaveChanges.flush(); // flush any queued changes
    window.removeEventListener('beforeunload', this.onBeforeUnload);
  }

  doSizePage() {
    window.document.body.style['min-width'] = '1000px';
  }
  
  doReplaceState() {
    const {balanceId} = this.state;
    const path = `/balancing/${balanceId}`;
    if (!this.props.disableHistory) {
      window.history.replaceState({}, null, path);
    }
  }

  // This method is throttled.
  doSaveChanges() {
    const {
      balanceId,
      stepIndex,
      schoolId,
      gradeLevelNextYear,
      educators,
      classroomsCount,
      planText,
      studentIdsByRoom,
      principalNotesText
    } = this.state;

    // Don't save until they choose a grade level and school
    if (!balanceId) return;
    if (!schoolId) return;
    if (!gradeLevelNextYear) return;
    const payload = {
      balanceId,
      stepIndex,
      schoolId,
      gradeLevelNextYear,
      educators,
      classroomsCount,
      planText,
      studentIdsByRoom,
      principalNotesText,
      clientNowMs: moment.utc().unix()
    };
    postClassroomsForGrade(payload);
{'fraction_non_alphanumeric': 0.10495549355652982, 'fraction_numerical': 0.0034542314335060447, 'mean_word_length': 3.4126611957796014, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '4040765', 'n_tokens_mistral': 2315, 'n_tokens_neox': 2211, 'n_words': 486}