<commit_before>// @flow weak
import React, { Component } from 'react';
import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import _ from 'lodash';
import Button from '../Button/Button';
import { updateForm } from '../../state/fundraiser/actions';
import FieldShape from '../FieldShape/FieldShape';

import type { Element } from 'react';
import type { Dispatch } from 'redux';
import type { AppState } from '../../state';

type OwnProps = {
  buttonText?: Element<any> | string,
  proceed?: () => void,
  fields: Object,
  formValues: Object,
  outstandingFields: any[],
  pageId: number,
  formId: number,
  form: Object,
  formId: number,
  updateForm: (form: Object) => void,
} & $Shape<mapStateToProps>;

type State = {
  errors: any,
  loading: boolean,
};
export class MemberDetailsForm extends Component<OwnProps, State> {
  static title = <FormattedMessage id="details" defaultMessage="details" />;

  HIDDEN_FIELDS = [
    'source',
    'akid',
    'referrer_id',
    'rid',
    'bucket',
    'referring_akid',
  ];

  constructor(props: OwnProps) {
    super(props);

    this.state = {
      errors: {},
      loading: false,
    };
  }

  componentDidMount() {
    this.prefill();
  }

  prefill() {
    const data = {};
    for (const field of this.props.fields) {
      data[field.name] = this.props.formValues[field.name]
        ? this.props.formValues[field.name]
        : field.default_value;
    }

    for (const name of this.HIDDEN_FIELDS) {
      if (this.props.formValues[name]) {
        data[name] = this.props.formValues[name];
      }
    }
    this.props.updateForm({ ...this.props.form, ...data });
  }

  getFieldError(field: string) {
    const error = this.state.errors[field];
    if (!error) return null;
    return <FormattedMessage {...error} />;
  }

  buttonText() {
    if (this.state.loading) {
      return (
        <FormattedMessage id="form.processing" defaultMessage="Processing..." />
      );
    } else if (this.props.buttonText) {
      return this.props.buttonText;
    } else {
      return <FormattedMessage id="form.submit" defaultMessage="Submit" />;
    }
  }

  handleSuccess() {
    this.setState({ errors: {} }, () => {
      if (this.props.proceed) {
        this.props.proceed();
      }
    });
  }

  handleFailure(response: any) {
    const errors = _.mapValues(response.errors, ([message]) => {
      return {
        id: 'errors.this_field_with_message',
        defaultMessage: 'This field {message}',
        values: { message },
      };
    });

    this.setState({ errors });
  }

  updateField(key, value) {
    this.state.errors[key] = null; // reset error message when field value changes
    this.props.updateForm({
      ...this.props.form,
      [key]: value,
    });
  }

  submit(e: SyntheticEvent<HTMLFormElement>) {
    this.setState({ loading: true });
    e.preventDefault();
    // HACKISH
    // Use a proper xhr lib if we want to make our lives easy.
    // Ideally a
    fetch(`/api/pages/${this.props.pageId}/actions/validate`, {
      method: 'POST',
      headers: {
        'content-type': 'application/json',
        accept: 'application/json',
      },
      body: JSON.stringify({ ...this.props.form, form_id: this.props.formId }),
    }).then(
      response => {
        this.setState({ loading: false });
        if (response.ok) {
          return response.json().then(this.handleSuccess.bind(this));
        }
        return response.json().then(this.handleFailure.bind(this));
      },
      failure => {
        this.setState({ loading: false });
      }
    );
  }

  fieldsToDisplay() {
    return this.props.fields.filter(field => {<commit_msg>Introduce `fundraiser:form:{success|error}` events<commit_after>// @flow weak
import React, { Component } from 'react';
import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import _ from 'lodash';
import Button from '../Button/Button';
import { updateForm } from '../../state/fundraiser/actions';
import FieldShape from '../FieldShape/FieldShape';
import ee from '../../shared/pub_sub';

import type { Element } from 'react';
import type { Dispatch } from 'redux';
import type { AppState } from '../../state';

type OwnProps = {
  buttonText?: Element<any> | string,
  proceed?: () => void,
  fields: Object,
  formValues: Object,
  outstandingFields: any[],
  pageId: number,
  formId: number,
  form: Object,
  formId: number,
  updateForm: (form: Object) => void,
} & $Shape<mapStateToProps>;

type State = {
  errors: any,
  loading: boolean,
};
export class MemberDetailsForm extends Component<OwnProps, State> {
  static title = <FormattedMessage id="details" defaultMessage="details" />;

  HIDDEN_FIELDS = [
    'source',
    'akid',
    'referrer_id',
    'rid',
    'bucket',
    'referring_akid',
  ];

  constructor(props: OwnProps) {
    super(props);

    this.state = {
      errors: {},
      loading: false,
    };
  }

  componentDidMount() {
    this.prefill();
  }

  prefill() {
    const data = {};
    for (const field of this.props.fields) {
      data[field.name] = this.props.formValues[field.name]
        ? this.props.formValues[field.name]
        : field.default_value;
    }

    for (const name of this.HIDDEN_FIELDS) {
      if (this.props.formValues[name]) {
        data[name] = this.props.formValues[name];
      }
    }
    this.props.updateForm({ ...this.props.form, ...data });
  }

  getFieldError(field: string) {
    const error = this.state.errors[field];
    if (!error) return null;
    return <FormattedMessage {...error} />;
  }

  buttonText() {
    if (this.state.loading) {
      return (
        <FormattedMessage id="form.processing" defaultMessage="Processing..." />
      );
    } else if (this.props.buttonText) {
      return this.props.buttonText;
    } else {
      return <FormattedMessage id="form.submit" defaultMessage="Submit" />;
    }
  }

  handleSuccess() {
    ee.emit('fundraiser:form:success');
    this.setState({ errors: {} }, () => {
      if (this.props.proceed) {
        this.props.proceed();
      }
    });
  }

  handleFailure(response: any) {
    ee.emit('fundraiser:form:error', response);
    const errors = _.mapValues(response.errors, ([message]) => {
      return {
        id: 'errors.this_field_with_message',
        defaultMessage: 'This field {message}',
        values: { message },
      };
    });

    this.setState({ errors });
  }

  updateField(key, value) {
    this.state.errors[key] = null; // reset error message when field value changes
    this.props.updateForm({
      ...this.props.form,
      [key]: value,
    });
  }

  submit(e: SyntheticEvent<HTMLFormElement>) {
    this.setState({ loading: true });
    e.preventDefault();
    // TODO
    // Use a proper xhr lib if we want to make our lives easy.
    fetch(`/api/pages/${this.props.pageId}/actions/validate`, {
      method: 'POST',
      headers: {
        'content-type': 'application/json',
        accept: 'application/json',
      },
      body: JSON.stringify({ ...this.props.form, form_id: this.props.formId }),
    }).then(
      response => {
        this.setState({ loading: false });
        if (response.ok) {
          return response.json().then(this.handleSuccess.bind(this));
        }
        return response.json().then(this.handleFailure.bind(this));
      },
      failure => {
        this.setState({ loading: false });
      }
    );
  }

  fieldsToDisplay() {
    return this.props.fields.filter(field => {
{'fraction_non_alphanumeric': 0.15880628830269117, 'fraction_numerical': 0.0, 'mean_word_length': 2.658382066276803, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 33, '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': '2403656', 'n_tokens_mistral': 2363, 'n_tokens_neox': 2346, 'n_words': 505}