<commit_before>/** @jsx React.DOM */

var AppIcon = require('../app_icon.js.jsx');
var Avatar = require('../avatar.js.jsx');
var Bounty = require('../bounty.js.jsx');
var MarkdownEditor = require('../markdown_editor.js.jsx');
var NewsFeedItemBountyClose = require('./news_feed_item_bounty_close.js.jsx');
var NewsFeedItemBountyCommentReference = require('./news_feed_item_bounty_comment_reference.js.jsx');
var NewsFeedItemBountyReviewReady = require('./news_feed_item_bounty_review_ready.js.jsx');
var NewsFeedItemBountyTimelineItem = require('./news_feed_item_bounty_timeline_item.js.jsx');
var NewsFeedItemBountyWin = require('./news_feed_item_bounty_win.js.jsx');
var NewsFeedItemComments = require('./news_feed_item_comments.js.jsx');
var ReadReceipts = require('../read_receipts.js.jsx');
var Spinner = require('../spinner.js.jsx');

module.exports = React.createClass({
  displayName: 'NewsFeedItemBountyModal',
  // (pletcher) TODO: Infer bounty, product, user, etc. from this.props.item
  propTypes: {
    bounty: React.PropTypes.object,
    item: React.PropTypes.object.isRequired,
    onHidden: React.PropTypes.func.isRequired,
    product: React.PropTypes.object,
    user: React.PropTypes.object
  },

  componentDidMount: function() {
    var modal = $(this.getDOMNode()).modal({ show: true });

    modal.on('hidden.bs.modal', this.props.onHidden);

    window.app.setCurrentAnalyticsProduct(this.props.product);

    analytics.track('product.wip.viewed', { bounty: this.props.bounty, news_feed: true });

    this.fetchBounty();
  },

  componentWillUnmount: function() {
    $(this.getDOMNode()).off('hidden.bs.modal');
  },

  fetchBounty: function(target) {
    target = target || this.props.item.target;

    var url = target.url + '.json';

    window.history.pushState({ url: target.url }, target.title, target.url);

    $(window).bind('popstate', function(e) {
      var state = window.history.state;

      if (!state) {
        $('.modal').modal('hide');
      }
    }.bind(this));

    $.get(url, function(response) {
      this.setState({
        bounty: response.bounty,
        events: response.events,
        ready: true
      });
    }.bind(this));
  },

  getDefaultProps: function() {
    var csrfTokenElement = document.getElementsByName('csrf-token')[0];

    if (csrfTokenElement) {
      return {
        csrf: csrfTokenElement.content
      };
    }

    console.warn('No CSRF token was found. Changes might fail to post.');

    return {};
  },

  getInitialState: function() {
    return {
      ready: false
    };
  },

  render: function() {
    // (pletcher) This is bad, but the WipSerializer needs to stay relatively
    // lightweight, and the TaskSerializer breaks on weird things (e.g.,
    // #contracts)
    var bounty = _.extend((this.state.bounty || {}), this.props.bounty);
    var product = this.props.product;

    bounty.product = product;
    bounty.user = this.props.user;

    // TODO: (pletcher) Don't render the bounty in a modal

    var title = <div className="clearfix">
      <div className="left mr2">
        <AppIcon app={product} />
      </div>
      <a href={'/' + product.slug}>{product.name}</a>
    </div>;

    return (
      <Lightbox size="modal-lg" title={title}>
        {this.state.ready ?
          [<Bounty
              key={bounty.id}
              bounty={bounty}
              noInvites={true}
              news_feed_item={this.props.item}
              valuation={{
                product: { name: product.name },
                url: '/' + product.slug + '/bounties',
                maxOffer: (6 * product.average_bounty),
                averageBounty: product.average_bounty,
                coinsMinted: product.coins_minted,
                profitLastMonth: product.profit_last_month
              }}
              show_coins={product.slug !== 'meta'} />,

          <div className="discussion" id="discussion-view-el" key={'discussion-' + bounty.id}>
            <div className="timeline omega">
              {this.renderDiscussion()}
            </div>
            {this.renderNewEventForm()}
          </div>] : <Spinner />}
      </Lightbox>
    );
  },

  renderCloseActions: function() {
    var bounty = this.state.bounty;

    if (bounty.can_close) {
      if (bounty.state === 'resolved') {
        return (
          <a className="btn btn-default" name="event_comment[type]" value="Event::Reopen" type="submit">
            Comment {' & '} Reopen
          </a>
        );
      }

      return (
        <a className="btn btn-default" name="event_comment[type]" value="Event::Close" type="submit">
          Comment {' & '} Close
        </a>
      );
    }
  },

  renderDiscussion: function() {
    var bounty = this.state.bounty;
    var product = this.props.item.product;
    var productSlug = product.slug;

    app.product = new Product(product);
    app.wip = new Wip(bounty);
    app.wipEvents = new WipEvents(this.state.events, {
      url: '/' + productSlug + '/bounties/' + bounty.number + '/comments'
    });

    app.discussionView = new DiscussionView({
      el: $('#discussion-view-el'),
      tipsPath: '/' + productSlug + '/tips',
      model: app.wip
    });

    var events = this.state.events.sort(function(a, b) {
      var aDate = new Date(a.timestamp);
      var bDate = new Date(b.timestamp);

      return aDate < bDate ? 1 : bDate < aDate ? -1 : 0;
    })

    return _.map(events, function(event, i) {
      var type = event.type;
      var renderedEvent;

      switch(event.type) {
      case 'Event::Allocation':
        renderedEvent = null;
        break;
      case 'Event::Close':
        renderedEvent = NewsFeedItemBountyClose(event);
        break;
      case 'Event::CommentReference':
        renderedEvent = NewsFeedItemBountyCommentReference(event);
        break;
      case 'Event::ReviewReady':
        renderedEvent = NewsFeedItemBountyReviewReady(event);
        break;
      case 'Event::Win':
        renderedEvent = NewsFeedItemBountyWin(event);
        break;
      default:
        renderedEvent = NewsFeedItemBountyTimelineItem(event);
        break;
      }

      if (i + 1 === events.length ) {
        var timestamp = (
          <div className="timeline-insert js-timestamp" key={'timestamp-' + this.props.bounty.id}><commit_msg>Fix comment sorting in zen mode<commit_after>/** @jsx React.DOM */

var AppIcon = require('../app_icon.js.jsx');
var Avatar = require('../avatar.js.jsx');
var Bounty = require('../bounty.js.jsx');
var MarkdownEditor = require('../markdown_editor.js.jsx');
var NewsFeedItemBountyClose = require('./news_feed_item_bounty_close.js.jsx');
var NewsFeedItemBountyCommentReference = require('./news_feed_item_bounty_comment_reference.js.jsx');
var NewsFeedItemBountyReviewReady = require('./news_feed_item_bounty_review_ready.js.jsx');
var NewsFeedItemBountyTimelineItem = require('./news_feed_item_bounty_timeline_item.js.jsx');
var NewsFeedItemBountyWin = require('./news_feed_item_bounty_win.js.jsx');
var NewsFeedItemComments = require('./news_feed_item_comments.js.jsx');
var ReadReceipts = require('../read_receipts.js.jsx');
var Spinner = require('../spinner.js.jsx');

module.exports = React.createClass({
  displayName: 'NewsFeedItemBountyModal',
  // (pletcher) TODO: Infer bounty, product, user, etc. from this.props.item
  propTypes: {
    bounty: React.PropTypes.object,
    item: React.PropTypes.object.isRequired,
    onHidden: React.PropTypes.func.isRequired,
    product: React.PropTypes.object,
    user: React.PropTypes.object
  },

  componentDidMount: function() {
    var modal = $(this.getDOMNode()).modal({ show: true });

    modal.on('hidden.bs.modal', this.props.onHidden);

    window.app.setCurrentAnalyticsProduct(this.props.product);

    analytics.track('product.wip.viewed', { bounty: this.props.bounty, news_feed: true });

    this.fetchBounty();
  },

  componentWillUnmount: function() {
    $(this.getDOMNode()).off('hidden.bs.modal');
  },

  fetchBounty: function(target) {
    target = target || this.props.item.target;

    var url = target.url + '.json';

    window.history.pushState({ url: target.url }, target.title, target.url);

    $(window).bind('popstate', function(e) {
      var state = window.history.state;

      if (!state) {
        $('.modal').modal('hide');
      }
    }.bind(this));

    $.get(url, function(response) {
      this.setState({
        bounty: response.bounty,
        events: response.events,
        ready: true
      });
    }.bind(this));
  },

  getDefaultProps: function() {
    var csrfTokenElement = document.getElementsByName('csrf-token')[0];

    if (csrfTokenElement) {
      return {
        csrf: csrfTokenElement.content
      };
    }

    console.warn('No CSRF token was found. Changes might fail to post.');

    return {};
  },

  getInitialState: function() {
    return {
      ready: false
    };
  },

  render: function() {
    // (pletcher) This is bad, but the WipSerializer needs to stay relatively
    // lightweight, and the TaskSerializer breaks on weird things (e.g.,
    // #contracts)
    var bounty = _.extend((this.state.bounty || {}), this.props.bounty);
    var product = this.props.product;

    bounty.product = product;
    bounty.user = this.props.user;

    // TODO: (pletcher) Don't render the bounty in a modal

    var title = <div className="clearfix">
      <div className="left mr2">
        <AppIcon app={product} />
      </div>
      <a href={'/' + product.slug}>{product.name}</a>
    </div>;

    return (
      <Lightbox size="modal-lg" title={title}>
        {this.state.ready ?
          [<Bounty
              key={bounty.id}
              bounty={bounty}
              noInvites={true}
              news_feed_item={this.props.item}
              valuation={{
                product: { name: product.name },
                url: '/' + product.slug + '/bounties',
                maxOffer: (6 * product.average_bounty),
                averageBounty: product.average_bounty,
                coinsMinted: product.coins_minted,
                profitLastMonth: product.profit_last_month
              }}
              show_coins={product.slug !== 'meta'} />,

          <div className="discussion" id="discussion-view-el" key={'discussion-' + bounty.id}>
            <div className="timeline omega">
              {this.renderDiscussion()}
            </div>
            {this.renderNewEventForm()}
          </div>] : <Spinner />}
      </Lightbox>
    );
  },

  renderCloseActions: function() {
    var bounty = this.state.bounty;

    if (bounty.can_close) {
      if (bounty.state === 'resolved') {
        return (
          <a className="btn btn-default" name="event_comment[type]" value="Event::Reopen" type="submit">
            Comment {' & '} Reopen
          </a>
        );
      }

      return (
        <a className="btn btn-default" name="event_comment[type]" value="Event::Close" type="submit">
          Comment {' & '} Close
        </a>
      );
    }
  },

  renderDiscussion: function() {
    var bounty = this.state.bounty;
    var product = this.props.item.product;
    var productSlug = product.slug;

    app.product = new Product(product);
    app.wip = new Wip(bounty);
    app.wipEvents = new WipEvents(this.state.events, {
      url: '/' + productSlug + '/bounties/' + bounty.number + '/comments'
    });

    app.discussionView = new DiscussionView({
      el: $('#discussion-view-el'),
      tipsPath: '/' + productSlug + '/tips',
      model: app.wip
    });

    var events = this.state.events.sort(function(a, b) {
      var aDate = new Date(a.timestamp);
      var bDate = new Date(b.timestamp);

      return aDate > bDate ? 1 : bDate > aDate ? -1 : 0;
    })

    return _.map(events, function(event, i) {
      var type = event.type;
      var renderedEvent;

      switch(event.type) {
      case 'Event::Allocation':
        renderedEvent = null;
        break;
      case 'Event::Close':
        renderedEvent = NewsFeedItemBountyClose(event);
        break;
      case 'Event::CommentReference':
        renderedEvent = NewsFeedItemBountyCommentReference(event);
        break;
      case 'Event::ReviewReady':
        renderedEvent = NewsFeedItemBountyReviewReady(event);
        break;
      case 'Event::Win':
        renderedEvent = NewsFeedItemBountyWin(event);
        break;
      default:
        renderedEvent = NewsFeedItemBountyTimelineItem(event);
        break;
      }

      if (i + 1 === events.length ) {
        var timestamp = (
          <div className="timeline-insert js-timestamp" key={'timestamp-' + this.props.bounty.id}>
{'fraction_non_alphanumeric': 0.14573422137646685, 'fraction_numerical': 0.0011100539169045353, 'mean_word_length': 2.591400911161731, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 45, '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': '5530468', 'n_tokens_mistral': 4066, 'n_tokens_neox': 3846, 'n_words': 754}