<commit_before>export default {
  isoName: 'fr',
  nativeName: 'Français',
  label: {
    clear: 'Effacer',
    ok: 'OK',
    cancel: 'Annuler',
    close: 'Fermer',
    set: 'Régler',
    select: 'Sélectionner',
    reset: 'Réinitialiser',
    remove: 'Supprimer',
    update: 'Mettre à jour',
    create: 'Créer',
    search: 'Rechercher',
    filter: 'Filtrer',
    refresh: 'Rafraîchir'
  },
  date: {
    days: 'Dimanche_Lundi_Mardi_Mercredi_Jeudi_Vendredi_Samedi'.split('_'),
    daysShort: 'Dim_Lun_Mar_Mer_Jeu_Ven_Sam'.split('_'),
    months: 'Janvier_Février_Mars_Avril_Mai_Juin_Juillet_Août_Septembre_Octobre_Novembre_Décembre'.split('_'),
    monthsShort: 'Jan_Fev_Mar_Avr_Mai_Juin_Jui_Aou_Sep_Oct_Nov_Dec'.split('_'),
    firstDayOfWeek: 1, // 0-6, 0 - Sunday, 1 Monday, ...
    format24h: true,
    pluralDay: 'jours'
  },
  table: {
    noData: 'Aucune donnée à afficher',
    noResults: 'Aucune donnée trouvée',
    loading: 'Chargement...',
    selectedRecords: function (rows) {
      return rows > 0
        ? rows + ' ' + (rows === 1 ? 'ligne sélectionnée' : 'lignes sélectionnées') + '.'
        : 'Aucune ligne sélectionnée.'
    },
    recordsPerPage: 'Lignes par page :',
    allRows: 'Tous',
    pagination: function (start, end, total) {
      return start + '-' + end + ' sur ' + total
    },
    columns: 'Colonnes'
  },
  editor: {
    url: 'URL',
    bold: 'Gras',
    italic: 'Italique',
    strikethrough: 'Barré',
    underline: 'Souligné',
    unorderedList: 'Liste non ordonnée',
    orderedList: 'Liste ordonnée',
    subscript: 'Indice',
    superscript: 'Exposant',
    hyperlink: 'Hyperlien',
    toggleFullscreen: 'Basculer en plein écran',
    quote: 'Citation',
    left: 'Aligner à gauche',
    center: 'Aligner au centre',
    right: 'Aligner à droite',
    justify: 'Justifier',
    print: 'Imprimer',
    outdent: "Diminuer l'indentation",
    indent: "Augmenter l'indentation",
    removeFormat: 'Supprimer la mise en forme',
    formatting: 'Mise en forme',
    fontSize: 'Taille de police',
    align: 'Aligner',
    hr: 'Insérer une règle horizontale',
    undo: 'Annuler',
    redo: 'Refaire',
    heading1: 'Titre 1',
    heading2: 'Titre 2',
    heading3: 'Titre 3',
    heading4: 'Titre 4',
    heading5: 'Titre 5',
    heading6: 'Titre 6',
    paragraph: 'Paragraphe',
    code: 'Code',
    size1: 'Très petit',
    size2: 'Petit',
    size3: 'Normal',
    size4: 'Moyenne',
    size5: 'Grand',
    size6: 'Très grand',
    size7: 'Maximum',
    defaultFont: 'Police par défaut',
    viewSource: 'Voir la source'
  },
  tree: {
    noData: 'Aucun nœud à afficher',
    noResults: 'Aucun nœud trouvé'
  }
}
<commit_msg>fix(lang): Correct date picker header date format for french #7991 (#8019)<commit_after>export default {
  isoName: 'fr',
  nativeName: 'Français',
  label: {
    clear: 'Effacer',
    ok: 'OK',
    cancel: 'Annuler',
    close: 'Fermer',
    set: 'Régler',
    select: 'Sélectionner',
    reset: 'Réinitialiser',
    remove: 'Supprimer',
    update: 'Mettre à jour',
    create: 'Créer',
    search: 'Rechercher',
    filter: 'Filtrer',
    refresh: 'Rafraîchir'
  },
  date: {
    days: 'Dimanche_Lundi_Mardi_Mercredi_Jeudi_Vendredi_Samedi'.split('_'),
    daysShort: 'Dim_Lun_Mar_Mer_Jeu_Ven_Sam'.split('_'),
    months: 'Janvier_Février_Mars_Avril_Mai_Juin_Juillet_Août_Septembre_Octobre_Novembre_Décembre'.split('_'),
    monthsShort: 'Jan_Fev_Mar_Avr_Mai_Juin_Jui_Aou_Sep_Oct_Nov_Dec'.split('_'),
    headerTitle: function (date, model) {
      return new Intl.DateTimeFormat('fr', {
        weekday: 'short', day: 'numeric', month: 'short'
      }).format(date)
    },
    firstDayOfWeek: 1, // 0-6, 0 - Sunday, 1 Monday, ...
    format24h: true,
    pluralDay: 'jours'
  },
  table: {
    noData: 'Aucune donnée à afficher',
    noResults: 'Aucune donnée trouvée',
    loading: 'Chargement...',
    selectedRecords: function (rows) {
      return rows > 0
        ? rows + ' ' + (rows === 1 ? 'ligne sélectionnée' : 'lignes sélectionnées') + '.'
        : 'Aucune ligne sélectionnée.'
    },
    recordsPerPage: 'Lignes par page :',
    allRows: 'Tous',
    pagination: function (start, end, total) {
      return start + '-' + end + ' sur ' + total
    },
    columns: 'Colonnes'
  },
  editor: {
    url: 'URL',
    bold: 'Gras',
    italic: 'Italique',
    strikethrough: 'Barré',
    underline: 'Souligné',
    unorderedList: 'Liste non ordonnée',
    orderedList: 'Liste ordonnée',
    subscript: 'Indice',
    superscript: 'Exposant',
    hyperlink: 'Hyperlien',
    toggleFullscreen: 'Basculer en plein écran',
    quote: 'Citation',
    left: 'Aligner à gauche',
    center: 'Aligner au centre',
    right: 'Aligner à droite',
    justify: 'Justifier',
    print: 'Imprimer',
    outdent: "Diminuer l'indentation",
    indent: "Augmenter l'indentation",
    removeFormat: 'Supprimer la mise en forme',
    formatting: 'Mise en forme',
    fontSize: 'Taille de police',
    align: 'Aligner',
    hr: 'Insérer une règle horizontale',
    undo: 'Annuler',
    redo: 'Refaire',
    heading1: 'Titre 1',
    heading2: 'Titre 2',
    heading3: 'Titre 3',
    heading4: 'Titre 4',
    heading5: 'Titre 5',
    heading6: 'Titre 6',
    paragraph: 'Paragraphe',
    code: 'Code',
    size1: 'Très petit',
    size2: 'Petit',
    size3: 'Normal',
    size4: 'Moyenne',
    size5: 'Grand',
    size6: 'Très grand',
    size7: 'Maximum',
    defaultFont: 'Police par défaut',
    viewSource: 'Voir la source'
  },
  tree: {
    noData: 'Aucun nœud à afficher',
    noResults: 'Aucun nœud trouvé'
  }
}
<|endoftext|>


<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 React, { Component } from "react";
import "./App.css";
import filesize from "filesize";

import {
  SearchBox,
  NoHits,
  Hits,
  HitsStats,
  SortingSelector,
  SelectedFilters,
  MenuFilter,
  Pagination,
  ResetFilters,
  SearchkitManager,
  SearchkitProvider,
  Tabs
} from "searchkit";

import { RefinementAutosuggest } from "@searchkit/refinement-autosuggest";

import {
  Layout,
  TopBar,
  LayoutBody,
  LayoutResults,
  ActionBar,
  ActionBarRow,
  SideBar
} from "searchkit";

import "searchkit/release/theme.css";

import contribute_json from "./contribute.json";
const KINTO_COLLECTION_URL =
  process.env.REACT_APP_KINTO_COLLECTION_URL ||
  "https://buildhub.prod.mozaws.net/v1/buckets/build-hub/collections/releases/";

const searchkit = new SearchkitManager(KINTO_COLLECTION_URL, {
  searchUrlPath: "search"
});

const HitsTable = ({ hits }) => {
  return (

            Product
            Version
            platform
            channel
            locale
            Tree
            Size
            Published on
            Build ID
            Revision

          {hits.map(
            ({
              _source: { build, download, source, target },
              _id,
              highlight
            }) => {
              const recordUrl = `${KINTO_COLLECTION_URL}records/${_id}`;
              const revisionUrl = source.revision ? (
                <a href={`${source.repository}/rev/${source.revision}`}>
                  {source.revision.substring(0, 6)}

              ) : (
                ""
              );
              const getHighlight = (title, value) => {
                return { __html: (highlight && highlight[title]) || value };
              };
              return (

                    <a href={`#${_id}`}>#

                  {source.tree}

                    {filesize(download.size)}

                      <time dateTime={download.date}>{download.date}</time>

                  {revisionUrl}

              );
            }
          )}

  );
};

const fullText = (query, options) => {
  if (!query) {
    return;
  }
  const fulltextQuery = query.startsWith("'")
    ? query.slice(1)
    : query
        .split(" ")
        .map(term => {
          return `${term}*`;
        })
        .join(" ");
  return {
    query_string: Object.assign({ query: fulltextQuery }, options)
  };
};

class ProjectInfo extends React.PureComponent {
  render() {
    const {
      repository: { url: source, license },
      participate: { docs: documentation },
      bugs: { report }
    } = contribute_json;

    return (

          Documentation

          Report a bug

            Source

    );
  }
}

class App extends Component {
  render() {
    return (

        <SearchkitProvider searchkit={searchkit}>
          <Layout>
            <TopBar>
              <SearchBox
                autofocus={true}
                searchOnChange={true}
                placeholder="e.g. firefox 54 linux"
                queryBuilder={fullText}
                queryOptions={{
                  analyzer: "standard",
                  default_operator: "AND",
                  phrase_slop: 1,
                  auto_generate_phrase_queries: true,
                  analyze_wildcard: true,
                  lenient: true,
                  split_on_whitespace: true
                }}
                queryFields={[
                  "source.product",
                  "target.channel^1.2",
                  "target.version^10",
                  "target.locale^3",
                  "target.platform^2",
                  "build.id"
                ]}
              />

                  ?

              <ProjectInfo />
            </TopBar>

            <LayoutBody>
              <SideBar>
                <RefinementAutosuggest
                  field="target.version"
                  title="Version"
                  git
                  id="versions"
                  size={20}
                  operator="OR"
                  multi={true}
                />
                <RefinementAutosuggest
                  field="target.platform"
                  title="Platform"
                  id="platform"
                  size={20}
                  multi={true}
                />
                <RefinementAutosuggest
                  field="target.channel"
                  title="Channel"
                  id="channel"
                  size={20}
                  multi={true}
                />
                <RefinementAutosuggest
                  field="target.locale"
                  title="Locale"
                  id="locale"
                  size={20}
                  multi={true}
                />
              </SideBar>

              <LayoutResults>
                <ActionBar>
                  <ActionBarRow>
                    <HitsStats />
                    <SortingSelector
                      options={[
                        {
                          label: "Published on",
                          field: "download.date",
                          order: "desc",
                          defaultOption: true
                        },
                        {
                          label: "Build date",
                          field: "build.date",
                          order: "desc"
                        }
                      ]}
                    />
                  </ActionBarRow>

                  <ActionBarRow>
                    <SelectedFilters />
                    <ResetFilters />
                  </ActionBarRow>

                  <MenuFilter
                    field="source.product"
                    title="Product"
                    id="products"
                    listComponent={Tabs}
                    translations={{ All: "All products" }}
                  />
                </ActionBar>

                <Hits
                  hitsPerPage={30}
                  listComponent={HitsTable}
                  highlightFields={[
                    "source.product",
                    "target.channel",
                    "target.version",
                    "target.locale",
                    "target.platform",
                    "build.id"
                  ]}
                />
                <NoHits
                  translations={{
                    "NoHits.NoResultsFound":
                      "No release found were found for {query}",
                    "NoHits.DidYouMean": "Search for {suggestion}",
                    "NoHits.SearchWithoutFilters":
                      "Search for {query} without filters"
                  }}
                  suggestionsField="target.version"
                />

                <Pagination showNumbers={true} />
              </LayoutResults>
            </LayoutBody>
          </Layout>
        </SearchkitProvider>

    );
  }
}

export default App;
<commit_msg>fix sorting in searchKit (#419)<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 React, { Component } from "react";
import "./App.css";
import filesize from "filesize";

import {
  SearchBox,
  NoHits,
  Hits,
  HitsStats,
  SortingSelector,
  SelectedFilters,
  MenuFilter,
  Pagination,
  ResetFilters,
  SearchkitManager,
  SearchkitProvider,
  Tabs
} from "searchkit";

import { RefinementAutosuggest } from "@searchkit/refinement-autosuggest";

import {
  Layout,
  TopBar,
  LayoutBody,
  LayoutResults,
  ActionBar,
  ActionBarRow,
  SideBar
} from "searchkit";

import "searchkit/release/theme.css";

import contribute_json from "./contribute.json";
const KINTO_COLLECTION_URL =
  process.env.REACT_APP_KINTO_COLLECTION_URL ||
  "https://buildhub.prod.mozaws.net/v1/buckets/build-hub/collections/releases/";

const searchkit = new SearchkitManager(KINTO_COLLECTION_URL, {
  searchUrlPath: "search"
});

const HitsTable = ({ hits }) => {
  return (

            Product
            Version
            platform
            channel
            locale
            Tree
            Size
            Published on
            Build ID
            Revision

          {hits.map(
            ({
              _source: { build, download, source, target },
              _id,
              highlight
            }) => {
              const recordUrl = `${KINTO_COLLECTION_URL}records/${_id}`;
              const revisionUrl = source.revision ? (
                <a href={`${source.repository}/rev/${source.revision}`}>
                  {source.revision.substring(0, 6)}

              ) : (
                ""
              );
              const getHighlight = (title, value) => {
                return { __html: (highlight && highlight[title]) || value };
              };
              return (

                    <a href={`#${_id}`}>#

                  {source.tree}

                    {filesize(download.size)}

                      <time dateTime={download.date}>{download.date}</time>

                  {revisionUrl}

              );
            }
          )}

  );
};

const fullText = (query, options) => {
  if (!query) {
    return;
  }
  const fulltextQuery = query.startsWith("'")
    ? query.slice(1)
    : query
        .split(" ")
        .map(term => {
          return `${term}*`;
        })
        .join(" ");
  return {
    query_string: Object.assign({ query: fulltextQuery }, options)
  };
};

class ProjectInfo extends React.PureComponent {
  render() {
    const {
      repository: { url: source, license },
      participate: { docs: documentation },
      bugs: { report }
    } = contribute_json;

    return (

          Documentation

          Report a bug

            Source

    );
  }
}

class App extends Component {
  render() {
    return (

        <SearchkitProvider searchkit={searchkit}>
          <Layout>
            <TopBar>
              <SearchBox
                autofocus={true}
                searchOnChange={true}
                placeholder="e.g. firefox 54 linux"
                queryBuilder={fullText}
                queryOptions={{
                  analyzer: "standard",
                  default_operator: "AND",
                  phrase_slop: 1,
                  auto_generate_phrase_queries: true,
                  analyze_wildcard: true,
                  lenient: true,
                  split_on_whitespace: true
                }}
                queryFields={[
                  "source.product",
                  "target.channel^1.2",
                  "target.version^10",
                  "target.locale^3",
                  "target.platform^2",
                  "build.id"
                ]}
              />

                  ?

              <ProjectInfo />
            </TopBar>

            <LayoutBody>
              <SideBar>
                <RefinementAutosuggest
                  field="target.version"
                  title="Version"
                  git
                  id="versions"
                  size={1000}
                  operator="OR"
                  multi={true}
                  orderKey={"_term"}
                  orderDirection={"desc"}
                />
                <RefinementAutosuggest
                  field="target.platform"
                  title="Platform"
                  id="platform"
                  size={1000}
                  orderKey="_term"
                  multi={true}
                />
                <RefinementAutosuggest
                  field="target.channel"
                  title="Channel"
                  id="channel"
                  size={1000}
                  orderKey="_term"
                  multi={true}
                />
                <RefinementAutosuggest
                  field="target.locale"
                  title="Locale"
                  id="locale"
                  size={1000}
                  orderKey="_term"
                  multi={true}
                />
              </SideBar>

              <LayoutResults>
                <ActionBar>
                  <ActionBarRow>
                    <HitsStats />
                    <SortingSelector
                      options={[
                        {
                          label: "Published on",
                          field: "download.date",
                          order: "desc",
                          defaultOption: true
                        },
                        {
                          label: "Build date",
                          field: "build.date",
                          order: "desc"
                        }
                      ]}
                    />
                  </ActionBarRow>

                  <ActionBarRow>
                    <SelectedFilters />
                    <ResetFilters />
                  </ActionBarRow>

                  <MenuFilter
                    field="source.product"
                    title="Product"
                    id="products"
                    listComponent={Tabs}
                    translations={{ All: "All products" }}
                  />
                </ActionBar>

                <Hits
                  hitsPerPage={30}
                  listComponent={HitsTable}
                  highlightFields={[
                    "source.product",
                    "target.channel",
                    "target.version",
                    "target.locale",
                    "target.platform",
                    "build.id"
                  ]}
                />
                <NoHits
                  translations={{
                    "NoHits.NoResultsFound":
                      "No release found were found for {query}",
                    "NoHits.DidYouMean": "Search for {suggestion}",
                    "NoHits.SearchWithoutFilters":
                      "Search for {query} without filters"
                  }}
                  suggestionsField="target.version"
                />

                <Pagination showNumbers={true} />
              </LayoutResults>
            </LayoutBody>
          </Layout>
        </SearchkitProvider>

    );
  }
}

export default App;
<|endoftext|>


<commit_before>/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
/*global easyXDM, window, escape, unescape */

/**
 * @class easyXDM.stack.HashTransport
 * HashTransport is a transport class that uses the IFrame URL Technique for communication.

 * http://msdn.microsoft.com/en-us/library/bb735305.aspx

 * @extends easyXDM.stack.TransportStackElement
 * @namespace easyXDM.stack
 * @constructor
 * @param {Object} config The transports configuration.
 * @cfg {String/Window} local The url to the local file used for proxying messages, or the local window.
 * @cfg {Number} delay The number of milliseconds to wait before firing onReady. To support using files other than hash.html for proxying messages.
 *
 */
easyXDM.stack.HashTransport = function(config){
    // #ifdef debug
    var trace = easyXDM.Debug.getTracer("easyXDM.stack.HashTransport");
    trace("constructor");
    // #endif
    var pub;
    var me = this, isHost, _timer, pollInterval, _lastMsg, _msgNr, _listenerWindow, _callerWindow;
    var usePolling, useParent, useResize, _remoteOrigin;

    function _sendMessage(message){
        // #ifdef debug
        trace("sending message '" + (_msgNr + 1) + " " + message + "' to " + _remoteOrigin);
        // #endif
        if (!_callerWindow) {
            // #ifdef debug
            trace("no caller window");
            // #endif
            return;
        }
        var url = config.remote + "#" + (_msgNr++) + "_" + message;

        if (isHost || !useParent) {
            // We are referencing an iframe
            _callerWindow.contentWindow.location = url;
            if (useResize) {
                // #ifdef debug
                trace("resizing to new size " + (_callerWindow.width > 75 ? 50 : 100));
                // #endif
                _callerWindow.width = _callerWindow.width > 75 ? 50 : 100;
            }
        }
        else {
            // We are referencing the parent window
            _callerWindow.location = url;
        }
    }

    function _handleHash(hash){
        _lastMsg = hash;
        // #ifdef debug
        trace("received message '" + _lastMsg + "' from " + _remoteOrigin);
        // #endif
        pub.up.incoming(_lastMsg.substring(_lastMsg.indexOf("_") + 1), _remoteOrigin);
    }

    function _onResize(e){
        // #ifdef debug
        trace("onresize: new message");
        // #endif
        _handleHash(_listenerWindow.location.hash);
    }

    /**
     * Checks location.hash for a new message and relays this to the receiver.
     * @private
     */
    function _pollHash(){
        if (_listenerWindow.location.hash && _listenerWindow.location.hash != _lastMsg) {
            // #ifdef debug
            trace("poll: new message");
            // #endif
            _handleHash(_listenerWindow.location.hash);
        }
    }

    function _attachListeners(){
        if (usePolling) {
            // #ifdef debug
            trace("starting polling");
            // #endif
            _timer = window.setInterval(_pollHash, pollInterval);
        }
        else {
            easyXDM.DomHelper.on(_listenerWindow, "resize", _onResize);
        }
    }

    /**
     * Calls the supplied onReady method

     * We delay this so that the the call to createChannel or createTransport will have completed.
     * @private
     */
    function _onReady(){
        if (!_listenerWindow) {
            if (!useParent) {
                // We must try obtain a reference to the correct window, this might fail
                try {
                    // This works in IE6
                    _listenerWindow = _callerWindow.contentWindow.frames["remote_" + config.channel];
                }
                catch (ex) {
                    // #ifdef debug
                    trace("Falling back to using window.open");
                    // #endif
                    _listenerWindow = window.open("", "remote_" + config.channel);
                }
            }
            if (!_listenerWindow) {
                // #ifdef debug
                trace("Failed to obtain a reference to the window");
                // #endif
                throw new Error("Failed to obtain a reference to the window");
            }
        }
        if (isHost) {
            _attachListeners();
        }
        pub.up.callback(true);
    }

    return (pub = {
        outgoing: function(message, domain){
            _sendMessage(encodeURIComponent(message));
        },
        destroy: function(){
            if (usePolling) {
                window.clearInterval(_timer);
            }
            else {
                easyXDM.DomHelper.un(_listenerWindow, "resize", _pollHash);
            }
            if (isHost || !useParent) {
                _callerWindow.parentNode.removeChild(_callerWindow);
            }
            _callerWindow = null;
        },
        init: function(){
            isHost = config.isHost;
            pollInterval = config.interval;
            _lastMsg = "#" + config.channel;
            _msgNr = 0;
            usePolling = config.usePolling;
            useParent = config.useParent;
            useResize = config.useResize;
            _remoteOrigin = easyXDM.Url.getLocation(config.remote);

            if (isHost) {
                if (useParent) {
                    _listenerWindow = window;
                }
                else {
                    // Fire the onReady method after a set delay
                    _timer = window.setTimeout(_onReady, config.delay);
                }
            }
            else {
                _listenerWindow = window;
                _attachListeners();
            }
            if (!isHost && useParent) {
                _callerWindow = parent;
                _onReady();
            }
            else {
                _callerWindow = easyXDM.DomHelper.createFrame((isHost ? config.remote : config.remote + "#" + config.channel), config.container, (isHost && !useParent) ? null : _onReady, (isHost ? "local_" : "remote_") + config.channel);
                if (isHost && !useParent) {
                    var tries = 0, max = config.delay / 50;
                    (function getRef(){
                        if (++tries > max) {
                            return;
                        }
                        if (_listenerWindow) {
                            return;
                        }
                        try {
                            // This works in IE6
                            _listenerWindow = _callerWindow.contentWindow.frames["remote_" + config.channel];
                            // #ifdef debug
                            trace("got an early reference to _listenerWindow");
                            // #endif
                            window.clearTimeout(_timer);
                            _onReady();
                            return;
                        }
                        catch (ex) {
                            window.setTimeout(getRef, 50);
                        }
                    }());
                }
            }

            // #ifdef debug
            if (usePolling) {
                trace("using polling to listen");
            }
            if (useResize) {
                trace("using resizing to call");
            }
            if (useParent) {
                trace("using current window as " + (config.local ? "listenerWindow" : "callerWindow"));
            }
            // #endif
        }
    });
};
<commit_msg>Refactored the HashTransport<commit_after>/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
/*global easyXDM, window, escape, unescape */

/**
 * @class easyXDM.stack.HashTransport
 * HashTransport is a transport class that uses the IFrame URL Technique for communication.

 * http://msdn.microsoft.com/en-us/library/bb735305.aspx

 * @extends easyXDM.stack.TransportStackElement
 * @namespace easyXDM.stack
 * @constructor
 * @param {Object} config The transports configuration.
 * @cfg {String/Window} local The url to the local file used for proxying messages, or the local window.
 * @cfg {Number} delay The number of milliseconds to wait before firing onReady. To support using files other than hash.html for proxying messages.
 *
 */
easyXDM.stack.HashTransport = function(config){
    // #ifdef debug
    var trace = easyXDM.Debug.getTracer("easyXDM.stack.HashTransport");
    trace("constructor");
    // #endif
    var pub;
    var me = this, isHost, _timer, pollInterval, _lastMsg, _msgNr, _listenerWindow, _callerWindow;
    var usePolling, useParent, useResize, _remoteOrigin;

    function _sendMessage(message){
        // #ifdef debug
        trace("sending message '" + (_msgNr + 1) + " " + message + "' to " + _remoteOrigin);
        // #endif
        if (!_callerWindow) {
            // #ifdef debug
            trace("no caller window");
            // #endif
            return;
        }
        var url = config.remote + "#" + (_msgNr++) + "_" + message;

        if (isHost || !useParent) {
            // We are referencing an iframe
            _callerWindow.contentWindow.location = url;
            if (useResize) {
                // #ifdef debug
                trace("resizing to new size " + (_callerWindow.width > 75 ? 50 : 100));
                // #endif
                _callerWindow.width = _callerWindow.width > 75 ? 50 : 100;
            }
        }
        else {
            // We are referencing the parent window
            _callerWindow.location = url;
        }
    }

    function _handleHash(hash){
        _lastMsg = hash;
        // #ifdef debug
        trace("received message '" + _lastMsg + "' from " + _remoteOrigin);
        // #endif
        pub.up.incoming(_lastMsg.substring(_lastMsg.indexOf("_") + 1), _remoteOrigin);
    }

    function _onResize(e){
        // #ifdef debug
        trace("onresize: new message");
        // #endif
        _handleHash(_listenerWindow.location.hash);
    }

    /**
     * Checks location.hash for a new message and relays this to the receiver.
     * @private
     */
    function _pollHash(){
        if (_listenerWindow.location.hash && _listenerWindow.location.hash != _lastMsg) {
            // #ifdef debug
            trace("poll: new message");
            // #endif
            _handleHash(_listenerWindow.location.hash);
        }
    }

    function _attachListeners(){
        if (usePolling) {
            // #ifdef debug
            trace("starting polling");
            // #endif
            _timer = window.setInterval(_pollHash, pollInterval);
        }
        else {
            easyXDM.DomHelper.on(_listenerWindow, "resize", _onResize);
        }
    }

    return (pub = {
        outgoing: function(message, domain){
            _sendMessage(encodeURIComponent(message));
        },
        destroy: function(){
            if (usePolling) {
                window.clearInterval(_timer);
            }
            else {
                easyXDM.DomHelper.un(_listenerWindow, "resize", _pollHash);
            }
            if (isHost || !useParent) {
                _callerWindow.parentNode.removeChild(_callerWindow);
            }
            _callerWindow = null;
        },
        init: function(){
            isHost = config.isHost;
            pollInterval = config.interval;
            _lastMsg = "#" + config.channel;
            _msgNr = 0;
            usePolling = config.usePolling;
            useParent = config.useParent;
            useResize = config.useResize;
            _remoteOrigin = easyXDM.Url.getLocation(config.remote);

            if (!isHost && useParent) {
                _listenerWindow = window;
                _callerWindow = parent;
                _attachListeners();
                pub.up.callback(true);
            }
            else {
                _callerWindow = easyXDM.DomHelper.createFrame((isHost ? config.remote : config.remote + "#" + config.channel), config.container, (isHost && useParent || !isHost) ? function(){
                    _listenerWindow = window;
                    _attachListeners();
                    pub.up.callback(true);
                }
 : null, (isHost ? "local_" : "remote_") + config.channel);

                if (isHost && !useParent) {
                    var tries = 0, max = config.delay / 50;
                    (function getRef(){
                        if (++tries > max) {
                            return;
                        }
                        if (_listenerWindow) {
                            return;
                        }
                        try {
                            // This works in IE6
                            _listenerWindow = _callerWindow.contentWindow.frames["remote_" + config.channel];
                            // #ifdef debug
                            trace("got an early reference to _listenerWindow");
                            // #endif
                            window.clearTimeout(_timer);
                            _attachListeners();
                            pub.up.callback(true);
                            return;
                        }
                        catch (ex) {
                            window.setTimeout(getRef, 50);
                        }
                    }());
                }
            }
        }
    });
};
<|endoftext|>


<commit_before>// @flow
import * as React from 'react'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import getMuiTheme from 'material-ui/styles/getMuiTheme'

import ScreensContainer from '../ScreensContainer'
import BottomBarContainer from '../BottomBarContainer'

const muiTheme = getMuiTheme({
  fontFamily: 'Roboto, sans-serif',
  palette: {
    primary1Color: '#eee',
    primary2Color: '#ddd',
    primary3Color: '#ccc',
    accent1Color: '#fff',
    accent2Color: '#eee',
    textColor: '#000',
    alternateTextColor: '#222',
    canvasColor: '#fff',
    borderColor: '#aaa',
    // disabledColor: fade(darkBlack, 0.3),
    pickerHeaderColor: '#000',
    // clockCircleColor: fade(darkBlack, 0.07),
    shadowColor: '#000',
  },
})

const App = () => (
  <MuiThemeProvider muiTheme={muiTheme}>

      <ScreensContainer />
      <BottomBarContainer />

  </MuiThemeProvider>
)

export default App
<commit_msg>Fix theme color<commit_after>// @flow
import * as React from 'react'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import getMuiTheme from 'material-ui/styles/getMuiTheme'

import ScreensContainer from '../ScreensContainer'
import BottomBarContainer from '../BottomBarContainer'

const muiTheme = getMuiTheme({
  fontFamily: 'Roboto, sans-serif',
  palette: {
    primary1Color: '#444',
    // primary2Color: '#ddd',
    // primary3Color: '#ccc',
    // accent1Color: '#fff',
    // accent2Color: '#eee',
    // textColor: '#000',
    // alternateTextColor: '#222',
    // canvasColor: '#fff',
    // borderColor: '#aaa',
    // disabledColor: fade(darkBlack, 0.3),
    // pickerHeaderColor: '#000',
    // clockCircleColor: fade(darkBlack, 0.07),
    // shadowColor: '#000',
  },
})

const App = () => (
  <MuiThemeProvider muiTheme={muiTheme}>

      <ScreensContainer />
      <BottomBarContainer />

  </MuiThemeProvider>
)

export default App
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import './App.css';
import DataExtractionTabs from './DatasetExtraction/DataExtractionTabs';
import ContainerBaseLearner from './containers/ContainerBaseLearner';
import NotificationSystem from 'react-notification-system';
import { Button, Modal, Form, FormGroup, FormControl,
  ControlLabel, Radio } from 'react-bootstrap';

function handleErrors(response) {
  if (!response.ok) {
    var error = new Error(response.statusText);

    // Unexpected error
    if (response.status === 500) {
      error.errMessage = 'Unexpected error';
      throw error;
    }
    return response.json()
      .then(errorBody => {
        error.errMessage = JSON.stringify(errorBody);
        throw error;
      });
  }
  return response;
}

class CreateProjectModal extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: '',
      selected: null
    };
  }

  render() {
    return (
      <Modal
        show={this.props.isOpen}
        onHide={this.props.onRequestClose}
      >
        <Modal.Header closeButton>
          <Modal.Title>Create New Project</Modal.Title>
        </Modal.Header>
        <Modal.Body>

Existing folders

          <Form><FormGroup>
            {this.props.folders.map((x) => {
              return (
                <Radio
                  name='directories'
                  key={x}
                  checked={this.state.selected === x}
                  onChange={() => this.setState({selected: x})}>
                  {x}
                </Radio>
              )
            })}
          </FormGroup></Form>
          <Form inline onSubmit={(e) => e.preventDefault()}>
            <FormGroup
              controlId='newProjectName'
            >
              <ControlLabel>{'Name new project '}</ControlLabel>
              {' '}
              <FormControl
                placeholder='Enter new project name'
                value={this.state.name}
                onChange={(evt) => this.setState({name: evt.target.value})}
              />
            </FormGroup>
            {' '}
            <Button
              disabled={!this.state.name}
              bsStyle='primary'
              onClick={() => {
                this.props.createProject(this.state.name);
              }}
            >
              Create
            </Button>
          </Form>
        </Modal.Body>
        <Modal.Footer>
          <Button
            disabled={!this.state.selected}
            bsStyle='primary'
            onClick={() => {
              this.props.changePath(this.state.selected);
              this.props.onRequestClose();
              this.props.addNotification({
                title: 'Success',
                message: 'Opened project ' + this.state.selected,
                level: 'success'
              })
            }}
          >
            Open project folder
          </Button>
          <Button onClick={this.props.onRequestClose}>Cancel</Button>
        </Modal.Footer>
      </Modal>
    )
  }
}

class NotebookWithToolbar extends Component {
  constructor(props) {
    super(props);
    this.state = {
      path: 'test',
      folders: [],
      showCreateProjectModal: false
    };
  }

  // Get request from server to populate fields
  componentDidMount() {
    this.getFolders();
  }

  // Get list of folders in current working directory
  getFolders() {
    fetch('/folders/')
    .then(response => response.json())
    .then(json => {
      console.log(json);
      this.setState({
        folders: json
      });
    });
  }

  // Creates new project folder with initialized xcnb.db
  createProject(name) {
    var payload = {ensemble_name: name};
    fetch(
      '/ensemble/',
      {
        method: "POST",
        body: JSON.stringify( payload ),
        headers: new Headers({
          'Content-Type': 'application/json'
        })
      }
    )
    .then(handleErrors)
    .then(response => response.json())
    .then(json => {
      console.log(json);
      this.props.addNotification({
        title: 'Success',
        message: 'Created new project folder',
        level: 'success'
      });
      this.getFolders();
    })
    .catch(error => {
      console.log(error.message);
      console.log(error.errMessage);
      this.props.addNotification({
        title: error.message,
        message: error.errMessage,
        level: 'error'
      });
    });
  }

  render() {
    return (

        <Button
          onClick={() => this.setState({showCreateProjectModal: true})}
        >
          Create/Open Project
        </Button>
        <Notebook
          path={this.state.path}
          addNotification={(notif) => this.props.addNotification(notif)}
        />
        <CreateProjectModal
          createProject={(name) => this.createProject(name)}
          folders={this.state.folders}
          isOpen={this.state.showCreateProjectModal}
          onRequestClose={() => this.setState({showCreateProjectModal: false})}
          changePath={(path) => this.setState({path})}
          addNotification={(notif) => this.props.addNotification(notif)}
        />

    );
  }
}

function Notebook(props) {
  return (

      <DataExtractionTabs
        path={props.path}
        addNotification={(notif) => props.addNotification(notif)}
      />
      <ContainerBaseLearner
        path={props.path}
        addNotification={(notif) => props.addNotification(notif)}
      />

  )
}

class App extends Component {

  constructor(props) {
    super(props);
    this._notificationSystem = null;
  }

  componentDidMount() {
    this._notificationSystem = this.refs.notificationSystem;
  }

  render() {
    return (

Xcessiv

        <NotebookWithToolbar
          addNotification={(notif) => this._notificationSystem.addNotification(notif)}
        />
        <NotificationSystem ref='notificationSystem' />

    )
  }
}

export default App;
<commit_msg>default project open is blank<commit_after>import React, { Component } from 'react';
import './App.css';
import DataExtractionTabs from './DatasetExtraction/DataExtractionTabs';
import ContainerBaseLearner from './containers/ContainerBaseLearner';
import NotificationSystem from 'react-notification-system';
import { Button, Modal, Form, FormGroup, FormControl,
  ControlLabel, Radio } from 'react-bootstrap';

function handleErrors(response) {
  if (!response.ok) {
    var error = new Error(response.statusText);

    // Unexpected error
    if (response.status === 500) {
      error.errMessage = 'Unexpected error';
      throw error;
    }
    return response.json()
      .then(errorBody => {
        error.errMessage = JSON.stringify(errorBody);
        throw error;
      });
  }
  return response;
}

class CreateProjectModal extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: '',
      selected: null
    };
  }

  render() {
    return (
      <Modal
        show={this.props.isOpen}
        onHide={this.props.onRequestClose}
      >
        <Modal.Header closeButton>
          <Modal.Title>Create New Project</Modal.Title>
        </Modal.Header>
        <Modal.Body>

Existing folders

          <Form><FormGroup>
            {this.props.folders.map((x) => {
              return (
                <Radio
                  name='directories'
                  key={x}
                  checked={this.state.selected === x}
                  onChange={() => this.setState({selected: x})}>
                  {x}
                </Radio>
              )
            })}
          </FormGroup></Form>
          <Form inline onSubmit={(e) => e.preventDefault()}>
            <FormGroup
              controlId='newProjectName'
            >
              <ControlLabel>{'Name new project '}</ControlLabel>
              {' '}
              <FormControl
                placeholder='Enter new project name'
                value={this.state.name}
                onChange={(evt) => this.setState({name: evt.target.value})}
              />
            </FormGroup>
            {' '}
            <Button
              disabled={!this.state.name}
              bsStyle='primary'
              onClick={() => {
                this.props.createProject(this.state.name);
              }}
            >
              Create
            </Button>
          </Form>
        </Modal.Body>
        <Modal.Footer>
          <Button
            disabled={!this.state.selected}
            bsStyle='primary'
            onClick={() => {
              this.props.changePath(this.state.selected);
              this.props.onRequestClose();
              this.props.addNotification({
                title: 'Success',
                message: 'Opened project ' + this.state.selected,
                level: 'success'
              })
            }}
          >
            Open project folder
          </Button>
          <Button onClick={this.props.onRequestClose}>Cancel</Button>
        </Modal.Footer>
      </Modal>
    )
  }
}

class NotebookWithToolbar extends Component {
  constructor(props) {
    super(props);
    this.state = {
      path: '',
      folders: [],
      showCreateProjectModal: false
    };
  }

  // Get request from server to populate fields
  componentDidMount() {
    this.getFolders();
  }

  // Get list of folders in current working directory
  getFolders() {
    fetch('/folders/')
    .then(response => response.json())
    .then(json => {
      console.log(json);
      this.setState({
        folders: json
      });
    });
  }

  // Creates new project folder with initialized xcnb.db
  createProject(name) {
    var payload = {ensemble_name: name};
    fetch(
      '/ensemble/',
      {
        method: "POST",
        body: JSON.stringify( payload ),
        headers: new Headers({
          'Content-Type': 'application/json'
        })
      }
    )
    .then(handleErrors)
    .then(response => response.json())
    .then(json => {
      console.log(json);
      this.props.addNotification({
        title: 'Success',
        message: 'Created new project folder',
        level: 'success'
      });
      this.getFolders();
    })
    .catch(error => {
      console.log(error.message);
      console.log(error.errMessage);
      this.props.addNotification({
        title: error.message,
        message: error.errMessage,
        level: 'error'
      });
    });
  }

  render() {
    return (

        <Button
          onClick={() => this.setState({showCreateProjectModal: true})}
        >
          Create/Open Project
        </Button>

{'Current open project folder: ' + this.state.path}

        {Boolean(this.state.path) &&
          <Notebook
            path={this.state.path}
            addNotification={(notif) => this.props.addNotification(notif)}
          />
        }
        <CreateProjectModal
          createProject={(name) => this.createProject(name)}
          folders={this.state.folders}
          isOpen={this.state.showCreateProjectModal}
          onRequestClose={() => this.setState({showCreateProjectModal: false})}
          changePath={(path) => this.setState({path})}
          addNotification={(notif) => this.props.addNotification(notif)}
        />

    );
  }
}

function Notebook(props) {
  return (

      <DataExtractionTabs
        path={props.path}
        addNotification={(notif) => props.addNotification(notif)}
      />
      <ContainerBaseLearner
        path={props.path}
        addNotification={(notif) => props.addNotification(notif)}
      />

  )
}

class App extends Component {

  constructor(props) {
    super(props);
    this._notificationSystem = null;
  }

  componentDidMount() {
    this._notificationSystem = this.refs.notificationSystem;
  }

  render() {
    return (

Xcessiv

        <NotebookWithToolbar
          addNotification={(notif) => this._notificationSystem.addNotification(notif)}
        />
        <NotificationSystem ref='notificationSystem' />

    )
  }
}

export default App;
<|endoftext|>


<commit_before>// @flow
import { connect } from 'react-redux';

import Floorplan from '../components/Floorplan';

function mapStateToProps(state: Object, props: Object) {
  return {
    seats: state.seats.seats,
    zoom: state.zoom.zoom,
  }
}

export default connect(
  mapStateToProps,
)(Floorplan);
<commit_msg>Add tooltip action dispatcher to Floorplan container.<commit_after>// @flow
import { connect } from 'react-redux';

import Floorplan from '../components/Floorplan';
import { showTooltip, hideTooltip } from '../actions/tooltip';

function mapStateToProps(state: Object, props: Object) {
  return {
    seats: state.seats.seats,
    zoom: state.zoom.zoom,
  }
}

function mapDispatchToProps(dispatch: Function) {
  return {
    showTooltip: (x: number, y:number, text: string ) => dispatch(showTooltip(x, y, text)),
    hideTooltip: () => dispatch(hideTooltip()),
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(Floorplan);
<|endoftext|>


<commit_before>import React, { PropTypes } from "react";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import ImmutablePropTypes from "react-immutable-proptypes";

import RoomActions from "../actions/RoomActions";

import RoomChat from "../components/RoomChat";
import RoomList from "../components/RoomList";
import RoomUserList from "../components/RoomUserList";

class RoomsPane extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        const { loginUserName, params, rooms, roomActions } = this.props;

        let roomName;
        let roomChat;

        if (params && params.roomNameHash) {
            roomName = rooms.getNameByHash(params.roomNameHash);

            const roomData = rooms.getByName(roomName);

            if (roomData) {
                const room = {
                    name: roomName,
                    membership: roomData.get("membership"),
                    messages:   roomData.get("messages"),
                    showUsers:  roomData.get("showUsers")
                };

                roomChat = (
                    <RoomChat
                        loginUserName={loginUserName}
                        room={room}
                        roomActions={roomActions}
                    />
                );
            }
        }

        return (

                <RoomList
                    rooms={rooms}
                    roomActions={roomActions}
                />

                    {roomChat}

        );
    }
}

RoomsPane.propTypes = {
    loginUserName: PropTypes.string.isRequired,
    params:        PropTypes.shape({
        roomNameHash: PropTypes.string
    }),
    rooms:       ImmutablePropTypes.record.isRequired,
    roomActions: PropTypes.object.isRequired
};

const mapStateToProps = (state) => ({
    loginUserName: state.login.get("username"),
    rooms:         state.rooms
});

const mapDispatchToProps = (dispatch) => ({
    roomActions: bindActionCreators(RoomActions, dispatch)
});

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(RoomsPane);
<commit_msg>Make RoomsPane a pure component.<commit_after>import React, { PropTypes } from "react";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import ImmutablePropTypes from "react-immutable-proptypes";

import RoomActions from "../actions/RoomActions";

import RoomChat from "../components/RoomChat";
import RoomList from "../components/RoomList";
import RoomUserList from "../components/RoomUserList";

const RoomsPane = (props) => {
    const { loginUserName, params, rooms, roomActions } = props;

    let roomName;
    let roomChat;

    if (params && params.roomNameHash) {
        roomName = rooms.getNameByHash(params.roomNameHash);

        const roomData = rooms.getByName(roomName);

        if (roomData) {
            const room = {
                name: roomName,
                membership: roomData.get("membership"),
                messages:   roomData.get("messages"),
                showUsers:  roomData.get("showUsers")
            };

            roomChat = (
                <RoomChat
                    loginUserName={loginUserName}
                    room={room}
                    roomActions={roomActions}
                />
            );
        }
    }

    return (

            <RoomList
                rooms={rooms}
                roomActions={roomActions}
            />

                {roomChat}

    );
};

RoomsPane.propTypes = {
    loginUserName: PropTypes.string.isRequired,
    params:        PropTypes.shape({
        roomNameHash: PropTypes.string
    }),
    rooms:       ImmutablePropTypes.record.isRequired,
    roomActions: PropTypes.object.isRequired
};

const mapStateToProps = (state) => ({
    loginUserName: state.login.get("username"),
    rooms:         state.rooms
});

const mapDispatchToProps = (dispatch) => ({
    roomActions: bindActionCreators(RoomActions, dispatch)
});

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(RoomsPane);
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {
  Grid,
} from 'semantic-ui-react';
import {
  Redirect,
  Prompt,
} from 'react-router-dom';

// Logic
import { getSNAPBenefits } from '../programs/federal/snap';
import { getHousingBenefit } from '../programs/state/massachusetts/housing';

// Object Manipulation
import { setNestedProperty } from '../utils/setNestedProperty';
import { cloneDeep } from 'lodash';

// Data
import { clientList } from '../config/dummyClients';
import { CLIENT_DEFAULTS } from '../utils/CLIENT_DEFAULTS';

// Our Components
import AlertSidebar from '../AlertSidebar'
import { CurrentIncomeStep } from '../forms/currentIncome';
import { CurrentExpensesStep } from '../forms/currentExpenses';
import { PredictionsStep } from '../forms/Predictions';
import { HouseholdStep } from '../forms/Household';
import { CurrentBenefitsStep } from '../forms/current-benefits';
import StepBar from '../components/StepBar';
import ResultsGraph from '../ResultsGraph';

class VisitPage extends Component {
  constructor(props) {
    super(props);

    const clientInfo = clientList.find( client => {
      return client.clientId === parseInt(this.props.match.params.clientId, 10);
    });

    this.state = {
        clientInfo: clientInfo,
        visitId: this.props.match.params.visitId,
        currentStep: 1,
        isBlocking: true,
        redirect: false,
        client : {
          ...CLIENT_DEFAULTS,
          snapAlert: 'good',
          housingAlert: 'good',
        },
        userChanged: {}
    };  // end this.state {}

    this.steps = [
      { title: 'Current Benefits', form: CurrentBenefitsStep, },
      { title: 'Household', form: HouseholdStep },
      { title: 'Current Income', form: CurrentIncomeStep },
      { title: 'Current Expenses', form: CurrentExpensesStep },
      { title: 'Predictions', form: PredictionsStep },
      { title: 'Results', form: ResultsGraph }
    ];  // end this.steps {}
  };  // End constructor()

  changeClient = (evnt, { route, name, value, checked, time }) => {

    route = route || name;

    var val = value;
    if ( typeof checked === 'boolean' ) { val = checked; }

    var client      = cloneDeep( this.state.client ),
        userChanged = {...this.state.userChanged},  // only 1 deep
        current     = client.current,
        future      = client.future,
        routeList   = route.split('/'),
        id          = routeList[0],  // `routeList` gets mutated
        newEvent    = { time: time, route: routeList, value: val };

    setNestedProperty(newEvent, {current, future}, this.state.userChanged[ id ]);
    // Only set if the input was valid...? For now, always.
    // Also, userChanged should be only one step deep
    if ( time === 'future' ) { userChanged[ id ] = true; }

    this.setState( prevState => ({ client: client, userChanged: userChanged }) );
  }  // End onClientChange()

  saveForm = (exitAfterSave) => {
    alert('Form saved (not really, this is a placeholder).');
    if (exitAfterSave) {
      this.setState({isBlocking: false, redirect: true});
    } else {
      this.setState({isBlocking: false});
    }
  }

  nextStep = () => {
    this.setState(prevState => ({
      currentStep: prevState.currentStep + 1
    }));
  };

  previousStep = () => {
    this.setState(prevState => ({
      currentStep: prevState.currentStep - 1
    }));
  };

  goToStep = (index) => {
    this.setState({ currentStep: index });
  }

  getCurrentStep = () => {
    var step = Math.max( 1, Math.min( this.steps.length, this.state.currentStep )) - 1;   //keep it between 1 and 8 and convert to 0 index
    var FormSection = this.steps[ step ].form;

    return (
      <FormSection currentStep={this.state.currentStep}
                   client={this.state.client}
                   nextStep={this.nextStep}
                   previousStep={this.previousStep}
                   changeClient={this.changeClient}
                   saveForm={this.saveForm} />
    );
  };  // End getCurrentStep()

  render() {

    return (

        <Prompt
          when={this.state.isBlocking}
          message='Are you sure you want to leave the page with unsaved changes?'
        />

        {this.state.redirect ?
          <Redirect to={`/detail/${this.state.clientInfo.clientId}`}/> :
          false
        }

        <Grid
          style={{ height: '100%', padding: '2em 0' }}
          verticalAlign='middle'
          container
        >
          <Grid.Row>
            <Grid.Column width={10}>

            </Grid.Column>
            <Grid.Column floated='right' width={6}>
            </Grid.Column>
          </Grid.Row>
          <Grid.Row>
            <Grid.Column width = {16}>
              <StepBar
                currentStepIndex={this.state.currentStep}
                steps={this.steps}
                goToStep={this.goToStep}
              />
            </Grid.Column>
          </Grid.Row>
          <Grid.Row>
            <Grid.Column width={12}>

                {this.getCurrentStep()}

            </Grid.Column>
            <Grid.Column width={4} style={{ height: '100%' }}>
              <AlertSidebar
                hasSnap={this.state.client.current.hasSnap}
                hasHousing={this.state.client.current.hasHousing}
                snapAlert={getSNAPBenefits(this.state.client)}
                housingAlert={getHousingBenefit(this.state.client)}
              />
            </Grid.Column>
          </Grid.Row>
        </Grid>

    )
  }
}

export default VisitPage
<commit_msg>Hide steps on tablet and mobile<commit_after>import React, { Component } from 'react';
import {
  Grid,
} from 'semantic-ui-react';
import {
  Redirect,
  Prompt,
} from 'react-router-dom';

// Logic
import { getSNAPBenefits } from '../programs/federal/snap';
import { getHousingBenefit } from '../programs/state/massachusetts/housing';

// Object Manipulation
import { setNestedProperty } from '../utils/setNestedProperty';
import { cloneDeep } from 'lodash';

// Data
import { clientList } from '../config/dummyClients';
import { CLIENT_DEFAULTS } from '../utils/CLIENT_DEFAULTS';

// Our Components
import AlertSidebar from '../AlertSidebar'
import { CurrentIncomeStep } from '../forms/currentIncome';
import { CurrentExpensesStep } from '../forms/currentExpenses';
import { PredictionsStep } from '../forms/Predictions';
import { HouseholdStep } from '../forms/Household';
import { CurrentBenefitsStep } from '../forms/current-benefits';
import StepBar from '../components/StepBar';
import ResultsGraph from '../ResultsGraph';

class VisitPage extends Component {
  constructor(props) {
    super(props);

    const clientInfo = clientList.find( client => {
      return client.clientId === parseInt(this.props.match.params.clientId, 10);
    });

    this.state = {
        clientInfo: clientInfo,
        visitId: this.props.match.params.visitId,
        currentStep: 1,
        isBlocking: true,
        redirect: false,
        client : {
          ...CLIENT_DEFAULTS,
          snapAlert: 'good',
          housingAlert: 'good',
        },
        userChanged: {}
    };  // end this.state {}

    this.steps = [
      { title: 'Current Benefits', form: CurrentBenefitsStep, },
      { title: 'Household', form: HouseholdStep },
      { title: 'Current Income', form: CurrentIncomeStep },
      { title: 'Current Expenses', form: CurrentExpensesStep },
      { title: 'Predictions', form: PredictionsStep },
      { title: 'Results', form: ResultsGraph }
    ];  // end this.steps {}
  };  // End constructor()

  changeClient = (evnt, { route, name, value, checked, time }) => {

    route = route || name;

    var val = value;
    if ( typeof checked === 'boolean' ) { val = checked; }

    var client      = cloneDeep( this.state.client ),
        userChanged = {...this.state.userChanged},  // only 1 deep
        current     = client.current,
        future      = client.future,
        routeList   = route.split('/'),
        id          = routeList[0],  // `routeList` gets mutated
        newEvent    = { time: time, route: routeList, value: val };

    setNestedProperty(newEvent, {current, future}, this.state.userChanged[ id ]);
    // Only set if the input was valid...? For now, always.
    // Also, userChanged should be only one step deep
    if ( time === 'future' ) { userChanged[ id ] = true; }

    this.setState( prevState => ({ client: client, userChanged: userChanged }) );
  }  // End onClientChange()

  saveForm = (exitAfterSave) => {
    alert('Form saved (not really, this is a placeholder).');
    if (exitAfterSave) {
      this.setState({isBlocking: false, redirect: true});
    } else {
      this.setState({isBlocking: false});
    }
  }

  nextStep = () => {
    this.setState(prevState => ({
      currentStep: prevState.currentStep + 1
    }));
  };

  previousStep = () => {
    this.setState(prevState => ({
      currentStep: prevState.currentStep - 1
    }));
  };

  goToStep = (index) => {
    this.setState({ currentStep: index });
  }

  getCurrentStep = () => {
    var step = Math.max( 1, Math.min( this.steps.length, this.state.currentStep )) - 1;   //keep it between 1 and 8 and convert to 0 index
    var FormSection = this.steps[ step ].form;

    return (
      <FormSection currentStep={this.state.currentStep}
                   client={this.state.client}
                   nextStep={this.nextStep}
                   previousStep={this.previousStep}
                   changeClient={this.changeClient}
                   saveForm={this.saveForm} />
    );
  };  // End getCurrentStep()

  render() {

    return (

        <Prompt
          when={this.state.isBlocking}
          message='Are you sure you want to leave the page with unsaved changes?'
        />

        {this.state.redirect ?
          <Redirect to={`/detail/${this.state.clientInfo.clientId}`}/> :
          false
        }

        <Grid
          style={{ height: '100%', padding: '2em 0' }}
          verticalAlign='middle'
          container
        >
          <Grid.Row>
            <Grid.Column width={10}>

            </Grid.Column>
            <Grid.Column floated='right' width={6}>
            </Grid.Column>
          </Grid.Row>
          <Grid.Row only='computer'>
            <Grid.Column width = {16}>
              <StepBar
                currentStepIndex={this.state.currentStep}
                steps={this.steps}
                goToStep={this.goToStep}
              />
            </Grid.Column>
          </Grid.Row>
          <Grid.Row>
            <Grid.Column width={12}>

                {this.getCurrentStep()}

            </Grid.Column>
            <Grid.Column width={4} style={{ height: '100%' }}>
              <AlertSidebar
                hasSnap={this.state.client.current.hasSnap}
                hasHousing={this.state.client.current.hasHousing}
                snapAlert={getSNAPBenefits(this.state.client)}
                housingAlert={getHousingBenefit(this.state.client)}
              />
            </Grid.Column>
          </Grid.Row>
        </Grid>

    )
  }
}

export default VisitPage
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {
  Container,
  Responsive,
} from 'semantic-ui-react';
import { Redirect } from 'react-router-dom';

// DATA MANAGEMENT
import { setNestedProperty } from '../utils/setNestedProperty';
import { cloneDeep } from 'lodash';
import { convertForUpdate } from '../utils/convertForUpdate';

// Data
// import { clientList } from '../config/dummyClients';
import { CLIENT_DEFAULTS } from '../utils/CLIENT_DEFAULTS';

// Our Components
// import AlertSidebar from '../AlertSidebar'
import BrowserLeaveListener from '../components/prompts/BrowserLeaveListener';
import ReactRouterLeaveListener from '../components/prompts/ReactRouterLeaveListener';
import ErrorListener from '../components/prompts/ErrorListener';
import FeedbackPrompt from '../components/prompts/FeedbackPrompt';
import FeedbackForm from '../components/prompts/FeedbackForm';
import { FeedbackAnytime } from '../components/prompts/FeedbackAnytime';
import { ResetAnytime } from '../components/prompts/ResetAnytime';
import { CurrentIncomeStep } from '../forms/CurrentIncome';
import { CurrentExpensesStep } from '../forms/CurrentExpenses';
import { PredictionsStep } from '../forms/Predictions';
import { HouseholdStep } from '../forms/Household';
import { CurrentBenefitsStep } from '../forms/CurrentBenefits';
import StepBar from '../components/StepBar';

class VisitPage extends Component {
  constructor (props) {
    super(props);

    var {
      match,
      clientData,
    } = this.props;

    this.state = {
      clientInfo:  match.params.clientId,
      visitId:     match.params.visitId,
      currentStep: 1,
      isBlocking:  false,
      redirect:    false,
      client:      clientData,
      // For `FeedbackPrompt`
      promptData:  {
        open:      false,  // Start as hidden
        message:   '',
        header:    '',
        leaveText: 'Reset',
        callback:  () => {},
      },
      feedbackFormRequested: false,
      // Hack for MVP
      oldHousing:            clientData.current.housing,
      userChanged:           {},
      snippets:              props.snippets,
    };  // end this.state {}

    this.steps = [
      {
        form:              CurrentBenefitsStep,
        key:               'currentBenefits',
        updateClientValue: this.changeCurrent,
      },
      {
        form:              HouseholdStep,
        key:               'household',
        updateClientValue: this.changeCurrent,
      },
      {
        form:              CurrentIncomeStep,
        key:               'currentIncome',
        updateClientValue: this.changeCurrent,
      },
      {
        form:              CurrentExpensesStep,
        key:               'currentExpenses',
        updateClientValue: this.changeCurrent,
      },
      {
        form:              PredictionsStep,
        key:               'predictions',
        updateClientValue: this.changeFuture,
      },//,
    //  { title: 'Graphs', form: ResultsGraph }
    ];  // end this.steps {}

  };  // End constructor()

  resetClientIfOk = (shouldReset) => {

    if (!shouldReset) {
      return;
    }

    this.setState({
      currentStep: 1,
      client:      cloneDeep(CLIENT_DEFAULTS),
      oldHousing:  CLIENT_DEFAULTS.current.housing,
      isBlocking:  false,
      userChanged: {},
    });

  };

  askToResetClient = (promptData) => {
    // If the user hasn't interacted with the form at all
    if (!this.state.isBlocking) {
      // just go to the start of the form
      this.goToStep(1);
    } else {
      // Otherwise, suggest the user submit feedback
      this.askForFeedback(this.resetClientIfOk, promptData);
    }
  };

  askForFeedback = (callback, promptText) => {

    // When user exits feedback prompt somehow,
    // close it before finishing the callback.
    var closePrompt = (isOk) => {
      this.setState({ promptData: { open: false }});
      callback(isOk);
    };

    this.setState({
      promptData: {
        ...promptText,
        open:     true,
        callback: closePrompt,
      },
    });

  };

  openFeedback = () => {
    this.setState({ feedbackFormRequested: true });
  };

  closeFeedback = () => {
    this.setState({ feedbackFormRequested: false });
  };

  updateClientValue = ({ route, value, time }) => {

    var client      = cloneDeep(this.state.client),
        userChanged = { ...this.state.userChanged },  // only 1 deep
        current     = client.current,
        future      = client.future,
        routeList   = route.split('/'),
        id          = routeList[ 0 ],  // `routeList` gets mutated
        newEvent    = { time: time, route: routeList, value: value };

    setNestedProperty(newEvent, { current, future }, this.state.userChanged[ id ]);
    // Only set if the input was valid...? For now, always.
    // Also, userChanged should be only one step deep
    if (time === 'future') {
      userChanged[ id ] = true;
    }

    // Hack for MVP (otherwise need dependency + history system)
    let oldHousing = this.state.oldHousing;
    if (route === 'housing') {
      // client housing should be right now
      oldHousing = client.current.housing;
    }

    if (client.current.hasSection8) {
      client.current.housing = 'voucher';
    } else {
      // Restore housing to previous value
      client.current.housing = oldHousing;
    }

    client.future.housing = client.current.housing;

    this.setState((prevState) => {
      return {
        client:      client,
        userChanged: userChanged,
        oldHousing:  oldHousing,
        // Form has been changed, data should now be downloadable
        // Warning sign for leaving forms should be shown
        isBlocking:  true,
      };
    });
  };  // End onClientChange()

  changeCurrent = (evnt, data) => {
    data.time = 'current';
    var newData = convertForUpdate(data);
    this.updateClientValue(newData);
  };

  changeFuture = (evnt, data) => {
    data.time = 'future';
    var newData = convertForUpdate(data);
    this.updateClientValue(newData);
  };

  // Implement once privacy and security are worked out
  saveForm = (exitAfterSave) => {
    alert('Form saved (not really, this is a placeholder).');
    if (exitAfterSave) {
      this.setState({ isBlocking: false, redirect: true });
    } else {
      this.setState({ isBlocking: false });
    }
  };

  scrollToTop = () => {
    document.body.scrollTop = 0; // For Safari
    document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE, and Opera
  };

  nextStep = () => {
    this.setState((prevState) => {
      return { currentStep: prevState.currentStep + 1 };
    });
    this.scrollToTop();
  };

  previousStep = () => {
    this.setState((prevState) => {
      return { currentStep: prevState.currentStep - 1 };
    });
    this.scrollToTop();
  };

  goToStep = (index) => {
    this.setState({ currentStep: index });
  };

  getCurrentStepIndex = () => {
    // Keep it between 1 and 8
    var numSteps      = this.steps.length,
        currStepIndex = this.state.currentStep,
        limitedByMin  = Math.min(numSteps, currStepIndex),
        limitedByMax  = Math.max(1, limitedByMin);
    // Convert to 0 index
    return limitedByMax - 1;
  };

  getCurrentStep = (navData) => {
    var stepIndex    = this.getCurrentStepIndex(),
        step         = this.steps[ stepIndex ],
        FormSection  = step.form,
        formSnippets = this.state.snippets[ step.key ];
    /** @todo With new interpolation, is this needed anymore? */
    formSnippets.langCode = this.state.snippets.langCode;

    return (

        <FormSection
          currentStep={ this.state.currentStep }
          client={ this.state.client }
          navData={ navData }
          updateClientValue={ step.updateClientValue }
          saveForm={ this.saveForm }
          askToResetClient={ this.askToResetClient }
          openFeedback={ this.openFeedback }
          snippets={ formSnippets } />
        <FeedbackAnytime openFeedback={ this.openFeedback } />
        <ResetAnytime askToResetClient={ this.askToResetClient } />

    );
  };  // End getCurrentStep()

  render() {

    var snippets  = this.state.snippets,
        prevData  = null,
        nextData  = null,
        stepIndex = this.getCurrentStepIndex();

    if (stepIndex !== 0) {
      prevData = {
        text:    snippets[ `previous_v1.0` ],
        onClick: this.previousStep,
      };
    }

    // If it's not the last step
    if (stepIndex !== (this.steps.length - 1)) {
      // use normal 'next' data
      nextData = {
        text:    snippets[ `next_v1.0` ],
        onClick: this.nextStep,
      };

    // Otherwise, set up to reset client
    } else {
      nextData = {
        text:    snippets[ `newClient_v1.0` ],
        onClick: this.askToResetClient,
      };
    }

    var navData = {
      left:   prevData,
      middle: null,
      right:  nextData,
    };

    return (

        {/* = PROMPTS & PROMPT TRIGGERS = */}
        {/* - Sometimes visible - */}
        {/* Triggered by `ReactRouterLeaveListener`,
         *`ResetAnytime`, or `ErrorListener` */}
        <FeedbackPrompt
          { ...this.state.promptData }
          isBlocking={ this.state.isBlocking }
          openFeedback={ this.openFeedback } />
        {/* Triggered by `FeedbackPrompt` & `FeedbackAnytime` */}
        <FeedbackForm
          isOpen={ this.state.feedbackFormRequested }
          close={ this.closeFeedback }
          data={ this.state.client } />

        {/* - Never visible - */}
        <ErrorListener
          callback={ this.resetClientIfOk }
          client={ this.state.client }
          askForFeedback={ this.askForFeedback } />
        {/* Browser nav - reload/back/unload. */}
        <BrowserLeaveListener isBlocking={ this.state.isBlocking } />
        {/* React nav buttons (Home/About) */}
        <ReactRouterLeaveListener
          askForFeedback={ this.askForFeedback }
          confirmer = { this.props.confirmer }
          isBlocking={ this.state.isBlocking } />

        {/* = LINKS? = */}
        {/* We should probably remove this. If we want to
         * do this we might do this a different way at this
         * point. Perhaps a user's page should be a route
         * in VisitPage? Like our form sections will be? */}
        { this.state.redirect ? (
          <Redirect to={ `/detail/${this.state.clientInfo.clientId}` } />
        ) : (
          false
        ) }

        {/* = SECTION = */}
        {/* `padding` here duplicates previous `<Grid>` styleing */}
        <Container
          id = { `cliff-effects-tool` }
          className='flex-item flex-column'
          style={{ padding: '42px 0' }}>
          <Responsive
            minWidth='874.5'
            style={{ padding: '14px 0' }}>
            <StepBar
              currentStepIndex={ this.state.currentStep }
              steps={ this.steps }
              goToStep={ this.goToStep }
              snippets={ this.state.snippets.stepBar } />
          </Responsive>

            { this.getCurrentStep(navData) }

        </Container>

    );
  }
}

export default VisitPage;
<commit_msg>Changes name, removes excess values<commit_after>import React, { Component } from 'react';
import {
  Container,
  Responsive,
} from 'semantic-ui-react';
import { Redirect } from 'react-router-dom';

// DATA MANAGEMENT
import { setNestedProperty } from '../utils/setNestedProperty';
import { cloneDeep } from 'lodash';
import { convertForUpdate } from '../utils/convertForUpdate';

// Data
// import { clientList } from '../config/dummyClients';
import { CLIENT_DEFAULTS } from '../utils/CLIENT_DEFAULTS';

// Our Components
// import AlertSidebar from '../AlertSidebar'
import BrowserLeaveListener from '../components/prompts/BrowserLeaveListener';
import ReactRouterLeaveListener from '../components/prompts/ReactRouterLeaveListener';
import ErrorListener from '../components/prompts/ErrorListener';
import FeedbackPrompt from '../components/prompts/FeedbackPrompt';
import FeedbackForm from '../components/prompts/FeedbackForm';
import { FeedbackAnytime } from '../components/prompts/FeedbackAnytime';
import { ResetAnytime } from '../components/prompts/ResetAnytime';
import { CurrentIncomeStep } from '../forms/CurrentIncome';
import { CurrentExpensesStep } from '../forms/CurrentExpenses';
import { PredictionsStep } from '../forms/Predictions';
import { HouseholdStep } from '../forms/Household';
import { CurrentBenefitsStep } from '../forms/CurrentBenefits';
import StepBar from '../components/StepBar';

class VisitPage extends Component {
  constructor (props) {
    super(props);

    var {
      match,
      clientData,
    } = this.props;

    this.state = {
      clientInfo:  match.params.clientId,
      visitId:     match.params.visitId,
      currentStep: 1,
      isBlocking:  false,
      redirect:    false,
      client:      clientData,
      // For `FeedbackPrompt`
      promptData:  {
        open:      false,  // Start as hidden
        message:   '',
        header:    '',
        leaveText: 'Reset',
        callback:  () => {},
      },
      feedbackFormRequested: false,
      // Hack for MVP
      oldHousing:            clientData.current.housing,
      userChanged:           {},
      snippets:              props.snippets,
    };  // end this.state {}

    this.steps = [
      {
        form:              CurrentBenefitsStep,
        key:               'currentBenefits',
        updateClientValue: this.changeCurrent,
      },
      {
        form:              HouseholdStep,
        key:               'household',
        updateClientValue: this.changeCurrent,
      },
      {
        form:              CurrentIncomeStep,
        key:               'currentIncome',
        updateClientValue: this.changeCurrent,
      },
      {
        form:              CurrentExpensesStep,
        key:               'currentExpenses',
        updateClientValue: this.changeCurrent,
      },
      {
        form:              PredictionsStep,
        key:               'predictions',
        updateClientValue: this.changeFuture,
      },//,
    //  { title: 'Graphs', form: ResultsGraph }
    ];  // end this.steps {}

  };  // End constructor()

  resetClientIfOk = (shouldReset) => {

    if (!shouldReset) {
      return;
    }

    this.setState({
      currentStep: 1,
      client:      cloneDeep(CLIENT_DEFAULTS),
      oldHousing:  CLIENT_DEFAULTS.current.housing,
      isBlocking:  false,
      userChanged: {},
    });

  };

  askToResetClient = (promptData) => {
    // If the user hasn't interacted with the form at all
    if (!this.state.isBlocking) {
      // just go to the start of the form
      this.goToStep(1);
    } else {
      // Otherwise, suggest the user submit feedback
      this.askForFeedback(this.resetClientIfOk, promptData);
    }
  };

  askForFeedback = (callback, promptText) => {

    // When user exits feedback prompt somehow,
    // close it before finishing the callback.
    var closePrompt = (isOk) => {
      this.setState({ promptData: { open: false }});
      callback(isOk);
    };

    this.setState({
      promptData: {
        ...promptText,
        open:     true,
        callback: closePrompt,
      },
    });

  };

  openFeedback = () => {
    this.setState({ feedbackFormRequested: true });
  };

  closeFeedback = () => {
    this.setState({ feedbackFormRequested: false });
  };

  updateClientValue = ({ route, value, time }) => {

    var clone       = cloneDeep(this.state.client),
        userChanged = { ...this.state.userChanged },  // only 1 deep
        routeList   = route.split('/'),
        id          = routeList[ 0 ],  // `routeList` gets mutated
        newEvent    = { time: time, route: routeList, value: value };

    setNestedProperty(newEvent, clone, this.state.userChanged[ id ]);
    // Only set if the input was valid...? For now, always.
    // Also, userChanged should be only one step deep
    if (time === 'future') {
      userChanged[ id ] = true;
    }

    // Hack for MVP (otherwise need dependency + history system)
    let oldHousing = this.state.oldHousing;
    if (route === 'housing') {
      // clone housing should be right now
      oldHousing = clone.current.housing;
    }

    if (clone.current.hasSection8) {
      clone.current.housing = 'voucher';
    } else {
      // Restore housing to previous value
      clone.current.housing = oldHousing;
    }

    clone.future.housing = clone.current.housing;

    this.setState((prevState) => {
      return {
        client:      clone,
        userChanged: userChanged,
        oldHousing:  oldHousing,
        // Form has been changed, data should now be downloadable
        // Warning sign for leaving forms should be shown
        isBlocking:  true,
      };
    });
  };  // End onClientChange()

  changeCurrent = (evnt, data) => {
    data.time = 'current';
    var newData = convertForUpdate(data);
    this.updateClientValue(newData);
  };

  changeFuture = (evnt, data) => {
    data.time = 'future';
    var newData = convertForUpdate(data);
    this.updateClientValue(newData);
  };

  // Implement once privacy and security are worked out
  saveForm = (exitAfterSave) => {
    alert('Form saved (not really, this is a placeholder).');
    if (exitAfterSave) {
      this.setState({ isBlocking: false, redirect: true });
    } else {
      this.setState({ isBlocking: false });
    }
  };

  scrollToTop = () => {
    document.body.scrollTop = 0; // For Safari
    document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE, and Opera
  };

  nextStep = () => {
    this.setState((prevState) => {
      return { currentStep: prevState.currentStep + 1 };
    });
    this.scrollToTop();
  };

  previousStep = () => {
    this.setState((prevState) => {
      return { currentStep: prevState.currentStep - 1 };
    });
    this.scrollToTop();
  };

  goToStep = (index) => {
    this.setState({ currentStep: index });
  };

  getCurrentStepIndex = () => {
    // Keep it between 1 and 8
    var numSteps      = this.steps.length,
        currStepIndex = this.state.currentStep,
        limitedByMin  = Math.min(numSteps, currStepIndex),
        limitedByMax  = Math.max(1, limitedByMin);
    // Convert to 0 index
    return limitedByMax - 1;
  };

  getCurrentStep = (navData) => {
    var stepIndex    = this.getCurrentStepIndex(),
        step         = this.steps[ stepIndex ],
        FormSection  = step.form,
        formSnippets = this.state.snippets[ step.key ];
    /** @todo With new interpolation, is this needed anymore? */
    formSnippets.langCode = this.state.snippets.langCode;

    return (

        <FormSection
          currentStep={ this.state.currentStep }
          client={ this.state.client }
          navData={ navData }
          updateClientValue={ step.updateClientValue }
          saveForm={ this.saveForm }
          askToResetClient={ this.askToResetClient }
          openFeedback={ this.openFeedback }
          snippets={ formSnippets } />
        <FeedbackAnytime openFeedback={ this.openFeedback } />
        <ResetAnytime askToResetClient={ this.askToResetClient } />

    );
  };  // End getCurrentStep()

  render() {

    var snippets  = this.state.snippets,
        prevData  = null,
        nextData  = null,
        stepIndex = this.getCurrentStepIndex();

    if (stepIndex !== 0) {
      prevData = {
        text:    snippets[ `previous_v1.0` ],
        onClick: this.previousStep,
      };
    }

    // If it's not the last step
    if (stepIndex !== (this.steps.length - 1)) {
      // use normal 'next' data
      nextData = {
        text:    snippets[ `next_v1.0` ],
        onClick: this.nextStep,
      };

    // Otherwise, set up to reset client
    } else {
      nextData = {
        text:    snippets[ `newClient_v1.0` ],
        onClick: this.askToResetClient,
      };
    }

    var navData = {
      left:   prevData,
      middle: null,
      right:  nextData,
    };

    return (

        {/* = PROMPTS & PROMPT TRIGGERS = */}
        {/* - Sometimes visible - */}
        {/* Triggered by `ReactRouterLeaveListener`,
         *`ResetAnytime`, or `ErrorListener` */}
        <FeedbackPrompt
          { ...this.state.promptData }
          isBlocking={ this.state.isBlocking }
          openFeedback={ this.openFeedback } />
        {/* Triggered by `FeedbackPrompt` & `FeedbackAnytime` */}
        <FeedbackForm
          isOpen={ this.state.feedbackFormRequested }
          close={ this.closeFeedback }
          data={ this.state.client } />

        {/* - Never visible - */}
        <ErrorListener
          callback={ this.resetClientIfOk }
          client={ this.state.client }
          askForFeedback={ this.askForFeedback } />
        {/* Browser nav - reload/back/unload. */}
        <BrowserLeaveListener isBlocking={ this.state.isBlocking } />
        {/* React nav buttons (Home/About) */}
        <ReactRouterLeaveListener
          askForFeedback={ this.askForFeedback }
          confirmer = { this.props.confirmer }
          isBlocking={ this.state.isBlocking } />

        {/* = LINKS? = */}
        {/* We should probably remove this. If we want to
         * do this we might do this a different way at this
         * point. Perhaps a user's page should be a route
         * in VisitPage? Like our form sections will be? */}
        { this.state.redirect ? (
          <Redirect to={ `/detail/${this.state.clientInfo.clientId}` } />
        ) : (
          false
        ) }

        {/* = SECTION = */}
        {/* `padding` here duplicates previous `<Grid>` styleing */}
        <Container
          id = { `cliff-effects-tool` }
          className='flex-item flex-column'
          style={{ padding: '42px 0' }}>
          <Responsive
            minWidth='874.5'
            style={{ padding: '14px 0' }}>
            <StepBar
              currentStepIndex={ this.state.currentStep }
              steps={ this.steps }
              goToStep={ this.goToStep }
              snippets={ this.state.snippets.stepBar } />
          </Responsive>

            { this.getCurrentStep(navData) }

        </Container>

    );
  }
}

export default VisitPage;
<|endoftext|>