<commit_before>React = require 'react'
Dialog = require 'modal-form/dialog'
MediaCard = require '../components/media-card'
{Markdown} = require 'markdownz'
apiClient = require 'panoptes-client/lib/api-client'

`import StepThrough from '../components/step-through';`

completedThisSession = {}
window?.tutorialsCompletedThisSession = completedThisSession

module.exports = React.createClass
  displayName: 'Tutorial'

  statics:
    find: (workflow) ->
      # Prefer fetching the tutorial for the workflow, if a workflow is given.
      if workflow?
        apiClient.type('tutorials').get workflow_id: workflow.id
          .then (tutorials) ->
            # Backwards compatibility for null kind values. We assume these are standard tutorials.
            onlyStandardTutorials = tutorials.filter (tutorial) ->
              tutorial.kind in ['tutorial', null]
            onlyStandardTutorials[0]
      else
        Promise.resolve()

    startIfNecessary: (tutorial, user, preferences, geordi) ->
        if tutorial?
          @checkIfCompleted(tutorial, user, preferences).then (completed) =>
            unless completed
              @start tutorial, user, preferences, geordi

    checkIfCompleted: (tutorial, user, preferences) ->
      if user?
        window.prefs = preferences
        Promise.resolve preferences?.preferences?.tutorials_completed_at?[tutorial.id]?
      else
        Promise.resolve completedThisSession[tutorial.id]?

    start: (tutorial, user, preferences, geordi) ->
      TutorialComponent = this

      if tutorial.steps.length isnt 0
        awaitTutorialMedia = tutorial.get 'attached_images'
          .catch ->
            # Checking for attached images throws if there are none.
            []
          .then (mediaResources) ->
            mediaByID = {}
            for mediaResource in mediaResources
              mediaByID[mediaResource.id] = mediaResource
            mediaByID

        awaitTutorialMedia.then (mediaByID) =>
          Dialog.alert(<TutorialComponent tutorial={tutorial} media={mediaByID} preferences={preferences} user={user} geordi={geordi} />, {
            className: 'tutorial-dialog',
            required: true,
            closeButton: true
          })
            .catch =>
              null # We don't really care if the user canceled or completed the tutorial.

  propTypes:
    geordi: React.PropTypes.object
    preferences: React.PropTypes.shape
      preferences: React.PropTypes.object
    tutorial: React.PropTypes.shape
      steps: React.PropTypes.arrayOf React.PropTypes.shape
        media: React.PropTypes.string
        content: React.PropTypes.string
    user: React.PropTypes.object

  getDefaultProps: ->
    geordi: {}
    media: {}
    preferences: null
    tutorial: {}
    user: null

  componentWillUnmount: ->
    @handleUnmount()

  render: ->
    isIE = 'ActiveXObject' of window
    if isIE
      tutorialStyle = height: '85vh'
    <StepThrough ref="stepThrough" className="tutorial-steps" style={tutorialStyle}>
      {for step, i in @props.tutorial.steps
        step._key ?= Math.random()
        <MediaCard key={step._key} className="tutorial-step" src={@props.media[step.media]?.src}>
          <Markdown>{step.content}</Markdown>
          <hr />
          <p style={textAlign: 'center'}>
            {if i is @props.tutorial.steps.length - 1
              <button type="submit" className="major-button">Let’s go!</button>
            else
              <button type="button" className="standard-button" onClick={@handleNextClick}>Continue</button>}
          </p>
        </MediaCard>}
    </StepThrough>

  handleNextClick: ->
    @refs.stepThrough.goNext()

  handleUnmount: ->
    now = new Date().toISOString()
    completedThisSession[@props.tutorial.id] = now

    if @props.user?
      projectPreferences = @props.preferences
      projectPreferences ?= apiClient.type('project_preferences').create
        links:
          project: project.id
        preferences: {}
      # Build this manually. Having an index (even as a strings) keys creates an array.
      projectPreferences.preferences ?= {}
      projectPreferences.preferences.tutorials_completed_at ?= {}
      projectPreferences.update "preferences.tutorials_completed_at.#{@props.tutorial.id}": now
      projectPreferences.save()

      @logToGeordi now

  logToGeordi: (datetime) ->
    @props.geordi.logEvent {
      type: "tutorial-completion"
      data: {
        tutorial: @props.tutorial.id
        tutorialCompleted: datetime
      }
    }<commit_msg>Tutorials don't need to create preferences<commit_after>React = require 'react'
Dialog = require 'modal-form/dialog'
MediaCard = require '../components/media-card'
{Markdown} = require 'markdownz'
apiClient = require 'panoptes-client/lib/api-client'

`import StepThrough from '../components/step-through';`

completedThisSession = {}
window?.tutorialsCompletedThisSession = completedThisSession

module.exports = React.createClass
  displayName: 'Tutorial'

  statics:
    find: (workflow) ->
      # Prefer fetching the tutorial for the workflow, if a workflow is given.
      if workflow?
        apiClient.type('tutorials').get workflow_id: workflow.id
          .then (tutorials) ->
            # Backwards compatibility for null kind values. We assume these are standard tutorials.
            onlyStandardTutorials = tutorials.filter (tutorial) ->
              tutorial.kind in ['tutorial', null]
            onlyStandardTutorials[0]
      else
        Promise.resolve()

    startIfNecessary: (tutorial, user, preferences, geordi) ->
        if tutorial?
          @checkIfCompleted(tutorial, user, preferences).then (completed) =>
            unless completed
              @start tutorial, user, preferences, geordi

    checkIfCompleted: (tutorial, user, preferences) ->
      if user?
        window.prefs = preferences
        Promise.resolve preferences?.preferences?.tutorials_completed_at?[tutorial.id]?
      else
        Promise.resolve completedThisSession[tutorial.id]?

    start: (tutorial, user, preferences, geordi) ->
      TutorialComponent = this

      if tutorial.steps.length isnt 0
        awaitTutorialMedia = tutorial.get 'attached_images'
          .catch ->
            # Checking for attached images throws if there are none.
            []
          .then (mediaResources) ->
            mediaByID = {}
            for mediaResource in mediaResources
              mediaByID[mediaResource.id] = mediaResource
            mediaByID

        awaitTutorialMedia.then (mediaByID) =>
          Dialog.alert(<TutorialComponent tutorial={tutorial} media={mediaByID} preferences={preferences} user={user} geordi={geordi} />, {
            className: 'tutorial-dialog',
            required: true,
            closeButton: true
          })
            .catch =>
              null # We don't really care if the user canceled or completed the tutorial.

  propTypes:
    geordi: React.PropTypes.object
    preferences: React.PropTypes.shape
      preferences: React.PropTypes.object
    tutorial: React.PropTypes.shape
      steps: React.PropTypes.arrayOf React.PropTypes.shape
        media: React.PropTypes.string
        content: React.PropTypes.string
    user: React.PropTypes.object

  getDefaultProps: ->
    geordi: {}
    media: {}
    preferences: null
    tutorial: {}
    user: null

  componentWillUnmount: ->
    @handleUnmount()

  render: ->
    isIE = 'ActiveXObject' of window
    if isIE
      tutorialStyle = height: '85vh'
    <StepThrough ref="stepThrough" className="tutorial-steps" style={tutorialStyle}>
      {for step, i in @props.tutorial.steps
        step._key ?= Math.random()
        <MediaCard key={step._key} className="tutorial-step" src={@props.media[step.media]?.src}>
          <Markdown>{step.content}</Markdown>
          <hr />
          <p style={textAlign: 'center'}>
            {if i is @props.tutorial.steps.length - 1
              <button type="submit" className="major-button">Let’s go!</button>
            else
              <button type="button" className="standard-button" onClick={@handleNextClick}>Continue</button>}
          </p>
        </MediaCard>}
    </StepThrough>

  handleNextClick: ->
    @refs.stepThrough.goNext()

  handleUnmount: ->
    now = new Date().toISOString()
    completedThisSession[@props.tutorial.id] = now

    if @props.user?
      projectPreferences = @props.preferences
      # Build this manually. Having an index (even as a strings) keys creates an array.
      projectPreferences.preferences ?= {}
      projectPreferences.preferences.tutorials_completed_at ?= {}
      projectPreferences.update "preferences.tutorials_completed_at.#{@props.tutorial.id}": now
      projectPreferences.save()

      @logToGeordi now

  logToGeordi: (datetime) ->
    @props.geordi.logEvent {
      type: "tutorial-completion"
      data: {
        tutorial: @props.tutorial.id
        tutorialCompleted: datetime
      }
    }
{'fraction_non_alphanumeric': 0.10652537646402677, 'fraction_numerical': 0.0011154489682097045, 'mean_word_length': 2.6226262626262624, 'pattern_counts': {'":': 2, '<': 31, '<?xml version=': 0, '>': 65, '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': '4412177', 'n_tokens_mistral': 2598, 'n_tokens_neox': 2471, 'n_words': 575}