<commit_before>/**
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

import 'es6-promise';
import 'isomorphic-fetch';
import * as React from 'react';
import {createStore, applyMiddleware} from 'redux';
import {connect, Provider} from 'react-redux';
import * as thunkMiddleware from 'redux-thunk';

import {gender} from 'camelot-unchained';

import FactionSelect from './components/FactionSelect';
import PlayerClassSelect from './components/PlayerClassSelect';
import RaceSelect from './components/RaceSelect';
import AttributesSelect from './components/AttributesSelect';

import reducer from './redux/modules/reducer';
import {RacesState, fetchRaces, selectRace, RaceInfo} from './redux/modules/races';
import {FactionsState, fetchFactions, selectFaction, FactionInfo} from './redux/modules/factions';
import {PlayerClassesState, fetchPlayerClasses, selectPlayerClass, PlayerClassInfo} from './redux/modules/playerClasses';
import {AttributesState, fetchAttributes, allocateAttributePoint, AttributeInfo, AttributeType, resetAttributes} from './redux/modules/attributes';
import {AttributeOffsetsState, fetchAttributeOffsets, AttributeOffsetInfo} from './redux/modules/attributeOffsets';
import {CharacterState, createCharacter, CharacterCreationModel, resetCharacter} from './redux/modules/character';
import {selectGender} from './redux/modules/genders';

const createStoreWithMiddleware = applyMiddleware(
  thunkMiddleware
)(createStore);

let store = createStoreWithMiddleware(reducer);

function select(state: any): any {
  return {
    racesState: state.races,
    playerClassesState: state.playerClasses,
    factionsState: state.factions,
    attributesState: state.attributes,
    attributeOffsetsState: state.attributeOffsets,
    gender: state.gender,
    characterState: state.character,
  }
}

export enum pages {
  FACTION_SELECT,
  RACE_SELECT,
  CLASS_SELECT,
  ATTRIBUTES
}

export interface CharacterCreationProps {
  apiKey: string;
  apiHost: string;
  apiVersion: number;
  shard: number;
  created: () => void;
  dispatch?: (action: any) => void;
  racesState?: RacesState;
  playerClassesState?: PlayerClassesState;
  factionsState?: FactionsState;
  attributesState?: AttributesState;
  attributeOffsetsState?: AttributeOffsetsState;
  gender?: gender;
  characterState?: CharacterState;
}

class CharacterCreation extends React.Component<CharacterCreationProps, any> {
  private faction$: any;
  private race$: any;
  private class$: any;

  constructor(props: any) {
    super(props);
    this.state = {page: pages.FACTION_SELECT}
  }

  create = () => {
    // try to create...
    let model: CharacterCreationModel = {
      name: (this.refs['name-input'] as any).value,
      race: this.props.racesState.selected.id,
      gender: this.props.gender,
      faction: this.props.factionsState.selected.id,
      archetype: this.props.playerClassesState.selected.id,
      shardID: this.props.shard,
      attributes: this.props.attributesState.attributes.reduce((acc: any, cur: AttributeInfo) => {
        if (cur.type !== AttributeType.Primary) return acc;
        if (typeof acc.name !== 'undefined') {
          let name = acc.name;
          let val = acc.allocatedPoints;
          acc = {};
          acc[name] = val;
        }
        if (typeof acc[cur.name] === 'undefined' || isNaN(acc[cur.name])) {
          acc[cur.name] = cur.allocatedPoints;
        } else {
          acc[cur.name] += cur.allocatedPoints;
        }
        return acc;
      }),
    }
    this.props.dispatch(createCharacter(model,
                        this.props.apiKey,
                        this.props.apiHost,
                        this.props.shard,
                        this.props.apiVersion));
  }


  componentWillMount() {
    this.props.dispatch(resetCharacter());
    this.props.dispatch(fetchFactions(this.props.apiHost, this.props.shard, this.props.apiVersion));
    this.props.dispatch(fetchRaces(this.props.apiHost, this.props.shard, this.props.apiVersion));
    this.props.dispatch(fetchPlayerClasses(this.props.apiHost, this.props.shard, this.props.apiVersion));
    this.props.dispatch(fetchAttributes(this.props.apiHost, this.props.shard, this.props.apiVersion));
    this.props.dispatch(fetchAttributeOffsets(this.props.apiHost, this.props.shard, this.props.apiVersion));
  }

  componentDidUpdate() {
    if (this.props.characterState.success) {
      this.props.created();
    }
  }

  selectFaction = (selected: FactionInfo) => {
    this.props.dispatch(selectFaction(selected));

    // reset race & class if they are not of the selected faction
    if (this.props.racesState.selected && this.props.racesState.selected.faction != selected.id) {
      this.props.dispatch(selectRace(null));
      this.props.dispatch(selectPlayerClass(null));
    }
  }<commit_msg>Bug Fix: Reset selections and spent attribute points on cancel character creation.<commit_after>/**
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

import 'es6-promise';
import 'isomorphic-fetch';
import * as React from 'react';
import {createStore, applyMiddleware} from 'redux';
import {connect, Provider} from 'react-redux';
import * as thunkMiddleware from 'redux-thunk';

import {gender} from 'camelot-unchained';

import FactionSelect from './components/FactionSelect';
import PlayerClassSelect from './components/PlayerClassSelect';
import RaceSelect from './components/RaceSelect';
import AttributesSelect from './components/AttributesSelect';

import reducer from './redux/modules/reducer';
import {RacesState, fetchRaces, selectRace, RaceInfo} from './redux/modules/races';
import {FactionsState, fetchFactions, selectFaction, FactionInfo} from './redux/modules/factions';
import {PlayerClassesState, fetchPlayerClasses, selectPlayerClass, PlayerClassInfo} from './redux/modules/playerClasses';
import {AttributesState, fetchAttributes, allocateAttributePoint, AttributeInfo, AttributeType, resetAttributes} from './redux/modules/attributes';
import {AttributeOffsetsState, fetchAttributeOffsets, AttributeOffsetInfo} from './redux/modules/attributeOffsets';
import {CharacterState, createCharacter, CharacterCreationModel, resetCharacter} from './redux/modules/character';
import {selectGender} from './redux/modules/genders';

const createStoreWithMiddleware = applyMiddleware(
  thunkMiddleware
)(createStore);

let store = createStoreWithMiddleware(reducer);

function select(state: any): any {
  return {
    racesState: state.races,
    playerClassesState: state.playerClasses,
    factionsState: state.factions,
    attributesState: state.attributes,
    attributeOffsetsState: state.attributeOffsets,
    gender: state.gender,
    characterState: state.character,
  }
}

export enum pages {
  FACTION_SELECT,
  RACE_SELECT,
  CLASS_SELECT,
  ATTRIBUTES
}

export interface CharacterCreationProps {
  apiKey: string;
  apiHost: string;
  apiVersion: number;
  shard: number;
  created: () => void;
  dispatch?: (action: any) => void;
  racesState?: RacesState;
  playerClassesState?: PlayerClassesState;
  factionsState?: FactionsState;
  attributesState?: AttributesState;
  attributeOffsetsState?: AttributeOffsetsState;
  gender?: gender;
  characterState?: CharacterState;
}

class CharacterCreation extends React.Component<CharacterCreationProps, any> {
  private faction$: any;
  private race$: any;
  private class$: any;

  constructor(props: any) {
    super(props);
    this.state = {page: pages.FACTION_SELECT}
  }

  create = () => {
    // try to create...
    let model: CharacterCreationModel = {
      name: (this.refs['name-input'] as any).value,
      race: this.props.racesState.selected.id,
      gender: this.props.gender,
      faction: this.props.factionsState.selected.id,
      archetype: this.props.playerClassesState.selected.id,
      shardID: this.props.shard,
      attributes: this.props.attributesState.attributes.reduce((acc: any, cur: AttributeInfo) => {
        if (cur.type !== AttributeType.Primary) return acc;
        if (typeof acc.name !== 'undefined') {
          let name = acc.name;
          let val = acc.allocatedPoints;
          acc = {};
          acc[name] = val;
        }
        if (typeof acc[cur.name] === 'undefined' || isNaN(acc[cur.name])) {
          acc[cur.name] = cur.allocatedPoints;
        } else {
          acc[cur.name] += cur.allocatedPoints;
        }
        return acc;
      }),
    }
    this.props.dispatch(createCharacter(model,
                        this.props.apiKey,
                        this.props.apiHost,
                        this.props.shard,
                        this.props.apiVersion));
  }


  componentWillMount() {
    this.props.dispatch(resetAttributes());
    this.props.dispatch(resetCharacter());
    this.props.dispatch(selectRace(null));
    this.props.dispatch(selectGender(null));
    this.props.dispatch(selectPlayerClass(null));
    this.props.dispatch(fetchFactions(this.props.apiHost, this.props.shard, this.props.apiVersion));
    this.props.dispatch(fetchRaces(this.props.apiHost, this.props.shard, this.props.apiVersion));
    this.props.dispatch(fetchPlayerClasses(this.props.apiHost, this.props.shard, this.props.apiVersion));
    this.props.dispatch(fetchAttributes(this.props.apiHost, this.props.shard, this.props.apiVersion));
    this.props.dispatch(fetchAttributeOffsets(this.props.apiHost, this.props.shard, this.props.apiVersion));
  }

  componentDidUpdate() {
    if (this.props.characterState.success) {
      this.props.created();
    }
  }

  selectFaction = (selected: FactionInfo) => {
    this.props.dispatch(selectFaction(selected));

    // reset race & class if they are not of the selected faction
    if (this.props.racesState.selected && this.props.racesState.selected.faction != selected.id) {
      this.props.dispatch(selectRace(null));
      this.props.dispatch(selectPlayerClass(null));
    }
  }
{'fraction_non_alphanumeric': 0.12022394656713487, 'fraction_numerical': 0.0009822217856792063, 'mean_word_length': 3.8278805120910384, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 15, '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': '7142802', 'n_tokens_mistral': 2960, 'n_tokens_neox': 2927, 'n_words': 651}