<commit_before>/* global jQuery */

/**
## jquery.flot.hover.js

This plugin is used for mouse hover and tap on a point of plot series.
It supports the following options:
```js
grid: {
    hoverable: false, //to trigger plothover event on mouse hover or tap on a point
    clickable: false //to trigger plotclick event on mouse hover
}
```

It listens to native mouse move event or click, as well as artificial generated
tap and touchevent.

When the mouse is over a point or a tap on a point is performed, that point or
the correscponding bar will be highlighted and a "plothover" event will be generated.

Custom "touchevent" is triggered when any touch interaction is made. Hover plugin
handles this events by unhighlighting all of the previously highlighted points and generates
"plothovercleanup" event to notify any part that is handling plothover (for exemple to cleanup
the tooltip from webcharts).
*/

(function($) {
    'use strict';

    var options = {
        grid: {
            hoverable: false,
            clickable: false
        }
    };

    var browser = $.plot.browser;

    var eventType = {
        click: 'click',
        hover: 'hover'
    }

    function init(plot) {
        var lastMouseMoveEvent;
        var highlights = [];

        function bindEvents(plot, eventHolder) {
            var o = plot.getOptions();

            if (o.grid.hoverable || o.grid.clickable) {
                eventHolder[0].addEventListener('touchevent', triggerCleanupEvent, false);
                eventHolder[0].addEventListener('tap', generatePlothoverEvent, false);
            }

            if (o.grid.clickable) {
                eventHolder.bind("click", onClick);
            }

            if (o.grid.hoverable) {
                eventHolder.bind("mousemove", onMouseMove);

                // Use bind, rather than .mouseleave, because we officially
                // still support jQuery 1.2.6, which doesn't define a shortcut
                // for mouseenter or mouseleave.  This was a bug/oversight that
                // was fixed somewhere around 1.3.x.  We can return to using
                // .mouseleave when we drop support for 1.2.6.

                eventHolder.bind("mouseleave", onMouseLeave);
            }
        }

        function shutdown(plot, eventHolder) {
            eventHolder[0].removeEventListener('tap', generatePlothoverEvent);
            eventHolder[0].removeEventListener('touchevent', triggerCleanupEvent);
            eventHolder.unbind("mousemove", onMouseMove);
            eventHolder.unbind("mouseleave", onMouseLeave);
            eventHolder.unbind("click", onClick);
            highlights = [];
        }

        function generatePlothoverEvent(e) {
            var o = plot.getOptions(),
                newEvent = new CustomEvent('mouseevent');

            //transform from touch event to mouse event format
            newEvent.pageX = e.detail.changedTouches[0].pageX;
            newEvent.pageY = e.detail.changedTouches[0].pageY;
            newEvent.clientX = e.detail.changedTouches[0].clientX;
            newEvent.clientY = e.detail.changedTouches[0].clientY;

            if (o.grid.hoverable) {
                doTriggerClickHoverEvent(newEvent, eventType.hover, 30);
            }
            return false;
        }

        function doTriggerClickHoverEvent(event, eventType, searchDistance) {
            var series = plot.getData();
            if (event !== undefined
                && series.length > 0
                && series[0].xaxis.c2p !== undefined
                && series[0].yaxis.c2p !== undefined) {
                var eventToTrigger = "plot" + eventType;
                var seriesFlag = eventType + "able";
                triggerClickHoverEvent(eventToTrigger, event,
                    function(i) {
                        return series[i][seriesFlag] !== false;
                    }, searchDistance);
            }
        }

        function onMouseMove(e) {
            lastMouseMoveEvent = e;
            plot.getPlaceholder()[0].lastMouseMoveEvent = e;
            doTriggerClickHoverEvent(e, eventType.hover);
        }

        function onMouseLeave(e) {
            lastMouseMoveEvent = undefined;
            plot.getPlaceholder()[0].lastMouseMoveEvent = undefined;
            triggerClickHoverEvent("plothover", e,
                function(i) {
                    return false;
                });
        }

        function onClick(e) {
            doTriggerClickHoverEvent(e, eventType.click);
        }

        function triggerCleanupEvent() {
            plot.unhighlight();
            plot.getPlaceholder().trigger('plothovercleanup');
        }

        // trigger click or hover event (they send the same parameters
        // so we share their code)
        function triggerClickHoverEvent(eventname, event, seriesFilter, searchDistance) {
            var options = plot.getOptions(),
                offset = plot.offset(),
                page = browser.getPageXY(event),
                canvasX = page.X - offset.left,
                canvasY = page.Y - offset.top,
                pos = plot.c2p({
                    left: canvasX,
                    top: canvasY
                }),
                distance = searchDistance !== undefined ? searchDistance : options.grid.mouseActiveRadius;

            pos.pageX = page.X;
            pos.pageY = page.Y;

            var item = plot.findNearbyItem(canvasX, canvasY, seriesFilter, distance);

            if (item) {
                // fill in mouse pos for any listeners out there
                item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left, 10);
                item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top, 10);
            }

            if (options.grid.autoHighlight) {
                // clear auto-highlights
                for (var i = 0; i < highlights.length; ++i) {
                    var h = highlights[i];
                    if ((h.auto === eventname &&
                        !(item && h.series === item.series &&
                            h.point[0] === item.datapoint[0] &&
                            h.point[1] === item.datapoint[1])) || !item) {
                        unhighlight(h.series, h.point);
                    }
                }

                if (item) {
                    highlight(item.series, item.datapoint, eventname);
                }
            }

            plot.getPlaceholder().trigger(eventname, [pos, item]);
        }

        function highlight(s, point, auto) {
            if (typeof s === "number") {
                s = plot.getData()[s];
            }

            if (typeof point === "number") {
                var ps = s.datapoints.pointsize;
                point = s.datapoints.points.slice(ps * point, ps * (point + 1));
            }

            var i = indexOfHighlight(s, point);
            if (i === -1) {
                highlights.push({
                    series: s,
                    point: point,
                    auto: auto
                });

                plot.triggerRedrawOverlay();
            } else if (!auto) {
                highlights[i].auto = false;
            }
        }

        function unhighlight(s, point) {
            if (s == null && point == null) {
                highlights = [];
                plot.triggerRedrawOverlay();
                return;
            }

            if (typeof s === "number") {
                s = plot.getData()[s];
            }

            if (typeof point === "number") {
                var ps = s.datapoints.pointsize;
                point = s.datapoints.points.slice(ps * point, ps * (point + 1));
            }

            var i = indexOfHighlight(s, point);
            if (i !== -1) {
                highlights.splice(i, 1);

                plot.triggerRedrawOverlay();
            }
        }

        function indexOfHighlight(s, p) {
            for (var i = 0; i < highlights.length; ++i) {
                var h = highlights[i];
                if (h.series === s &&
                    h.point[0] === p[0] &&
                    h.point[1] === p[1]) {
                    return i;
                }
            }

            return -1;
        }

        function processDatapoints() {
            triggerCleanupEvent();
            doTriggerClickHoverEvent(lastMouseMoveEvent, eventType.hover);
        }

        function drawOverlay(plot, octx, overlay) {
            var plotOffset = plot.getPlotOffset(),
                i, hi;

            octx.save();
            octx.translate(plotOffset.left, plotOffset.top);
            for (i = 0; i < highlights.length; ++i) {
                hi = highlights[i];

                if (hi.series.bars.show) drawBarHighlight(hi.series, hi.point, octx);
                else drawPointHighlight(hi.series, hi.point, octx, plot);
            }
            octx.restore();
        }

        function drawPointHighlight(series, point, octx, plot) {
            var x = point[0],
                y = point[1],
                axisx = series.xaxis,
                axisy = series.yaxis,
                highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString();

            if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) {
                return;
            }

            var pointRadius = series.points.radius + series.points.lineWidth / 2;
            octx.lineWidth = pointRadius;
            octx.strokeStyle = highlightColor;
            var radius = 1.5 * pointRadius;
            x = axisx.p2c(x);
            y = axisy.p2c(y);

            octx.beginPath();
            var symbol = series.points.symbol;
            if (symbol === 'circle') {
                octx.arc(x, y, radius, 0, 2 * Math.PI, false);
            } else if (typeof symbol === 'string' && plot.drawSymbol && plot.drawSymbol[symbol]) {
                plot.drawSymbol[symbol](octx, x, y, radius, false);
            }

            octx.closePath();
            octx.stroke();
        }

        function drawBarHighlight(series, point, octx) {
            var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(),
                fillStyle = highlightColor,
                barLeft;

            var barWidth = series.bars.barWidth[0] || series.bars.barWidth;
            switch (series.bars.align) {
                case "left":
                    barLeft = 0;
                    break;
                case "right":
                    barLeft = -barWidth;
                    break;
                default:
                    barLeft = -barWidth / 2;
            }

            octx.lineWidth = series.bars.lineWidth;
            octx.strokeStyle = highlightColor;

            var fillTowards = series.bars.fillTowards || 0,
                bottom = fillTowards > series.yaxis.min ? Math.min(series.yaxis.max, fillTowards) : series.yaxis.min;

            $.plot.drawSeries.drawBar(point[0], point[1], point[2] || bottom, barLeft, barLeft + barWidth,
                function() {
                    return fillStyle;
                }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
        }

        function initHover(plot, options) {
            plot.highlight = highlight;
            plot.unhighlight = unhighlight;
            if (options.grid.hoverable || options.grid.clickable) {
                plot.hooks.drawOverlay.push(drawOverlay);
                plot.hooks.processDatapoints.push(processDatapoints);
            }

            lastMouseMoveEvent = plot.getPlaceholder()[0].lastMouseMoveEvent;
        }

        plot.hooks.bindEvents.push(bindEvents);
        plot.hooks.shutdown.push(shutdown);
        plot.hooks.processOptions.push(initHover);
    }

    $.plot.plugins.push({
        init: init,
        options: options,
        name: 'hover',
        version: '0.1'
    });
})(jQuery);
<commit_msg>Undo unintended change<commit_after>/* global jQuery */

/**
## jquery.flot.hover.js

This plugin is used for mouse hover and tap on a point of plot series.
It supports the following options:
```js
grid: {
    hoverable: false, //to trigger plothover event on mouse hover or tap on a point
    clickable: false //to trigger plotclick event on mouse hover
}
```

It listens to native mouse move event or click, as well as artificial generated
tap and touchevent.

When the mouse is over a point or a tap on a point is performed, that point or
the correscponding bar will be highlighted and a "plothover" event will be generated.

Custom "touchevent" is triggered when any touch interaction is made. Hover plugin
handles this events by unhighlighting all of the previously highlighted points and generates
"plothovercleanup" event to notify any part that is handling plothover (for exemple to cleanup
the tooltip from webcharts).
*/

(function($) {
    'use strict';

    var options = {
        grid: {
            hoverable: false,
            clickable: false
        }
    };

    var browser = $.plot.browser;

    var eventType = {
        click: 'click',
        hover: 'hover'
    }

    function init(plot) {
        var lastMouseMoveEvent;
        var highlights = [];

        function bindEvents(plot, eventHolder) {
            var o = plot.getOptions();

            if (o.grid.hoverable || o.grid.clickable) {
                eventHolder[0].addEventListener('touchevent', triggerCleanupEvent, false);
                eventHolder[0].addEventListener('tap', generatePlothoverEvent, false);
            }

            if (o.grid.clickable) {
                eventHolder.bind("click", onClick);
            }

            if (o.grid.hoverable) {
                eventHolder.bind("mousemove", onMouseMove);

                // Use bind, rather than .mouseleave, because we officially
                // still support jQuery 1.2.6, which doesn't define a shortcut
                // for mouseenter or mouseleave.  This was a bug/oversight that
                // was fixed somewhere around 1.3.x.  We can return to using
                // .mouseleave when we drop support for 1.2.6.

                eventHolder.bind("mouseleave", onMouseLeave);
            }
        }

        function shutdown(plot, eventHolder) {
            eventHolder[0].removeEventListener('tap', generatePlothoverEvent);
            eventHolder[0].removeEventListener('touchevent', triggerCleanupEvent);
            eventHolder.unbind("mousemove", onMouseMove);
            eventHolder.unbind("mouseleave", onMouseLeave);
            eventHolder.unbind("click", onClick);
            highlights = [];
        }

        function generatePlothoverEvent(e) {
            var o = plot.getOptions(),
                newEvent = new CustomEvent('mouseevent');

            //transform from touch event to mouse event format
            newEvent.pageX = e.detail.changedTouches[0].pageX;
            newEvent.pageY = e.detail.changedTouches[0].pageY;
            newEvent.clientX = e.detail.changedTouches[0].clientX;
            newEvent.clientY = e.detail.changedTouches[0].clientY;

            if (o.grid.hoverable) {
                doTriggerClickHoverEvent(newEvent, eventType.hover, 30);
            }
            return false;
        }

        function doTriggerClickHoverEvent(event, eventType, searchDistance) {
            var series = plot.getData();
            if (event !== undefined
                && series.length > 0
                && series[0].xaxis.c2p !== undefined
                && series[0].yaxis.c2p !== undefined) {
                var eventToTrigger = "plot" + eventType;
                var seriesFlag = eventType + "able";
                triggerClickHoverEvent(eventToTrigger, event,
                    function(i) {
                        return series[i][seriesFlag] !== false;
                    }, searchDistance);
            }
        }

        function onMouseMove(e) {
            lastMouseMoveEvent = e;
            plot.getPlaceholder()[0].lastMouseMoveEvent = e;
            doTriggerClickHoverEvent(e, eventType.hover);
        }

        function onMouseLeave(e) {
            lastMouseMoveEvent = undefined;
            plot.getPlaceholder()[0].lastMouseMoveEvent = undefined;
            triggerClickHoverEvent("plothover", e,
                function(i) {
                    return false;
                });
        }

        function onClick(e) {
            doTriggerClickHoverEvent(e, eventType.click);
        }

        function triggerCleanupEvent() {
            plot.unhighlight();
            plot.getPlaceholder().trigger('plothovercleanup');
        }

        // trigger click or hover event (they send the same parameters
        // so we share their code)
        function triggerClickHoverEvent(eventname, event, seriesFilter, searchDistance) {
            var options = plot.getOptions(),
                offset = plot.offset(),
                page = browser.getPageXY(event),
                canvasX = page.X - offset.left,
                canvasY = page.Y - offset.top,
                pos = plot.c2p({
                    left: canvasX,
                    top: canvasY
                }),
                distance = searchDistance !== undefined ? searchDistance : options.grid.mouseActiveRadius;

            pos.pageX = page.X;
            pos.pageY = page.Y;

            var item = plot.findNearbyItem(canvasX, canvasY, seriesFilter, distance);

            if (item) {
                // fill in mouse pos for any listeners out there
                item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left, 10);
                item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top, 10);
            }

            if (options.grid.autoHighlight) {
                // clear auto-highlights
                for (var i = 0; i < highlights.length; ++i) {
                    var h = highlights[i];
                    if ((h.auto === eventname &&
                        !(item && h.series === item.series &&
                            h.point[0] === item.datapoint[0] &&
                            h.point[1] === item.datapoint[1])) || !item) {
                        unhighlight(h.series, h.point);
                    }
                }

                if (item) {
                    highlight(item.series, item.datapoint, eventname);
                }
            }

            plot.getPlaceholder().trigger(eventname, [pos, item]);
        }

        function highlight(s, point, auto) {
            if (typeof s === "number") {
                s = plot.getData()[s];
            }

            if (typeof point === "number") {
                var ps = s.datapoints.pointsize;
                point = s.datapoints.points.slice(ps * point, ps * (point + 1));
            }

            var i = indexOfHighlight(s, point);
            if (i === -1) {
                highlights.push({
                    series: s,
                    point: point,
                    auto: auto
                });

                plot.triggerRedrawOverlay();
            } else if (!auto) {
                highlights[i].auto = false;
            }
        }

        function unhighlight(s, point) {
            if (s == null && point == null) {
                highlights = [];
                plot.triggerRedrawOverlay();
                return;
            }

            if (typeof s === "number") {
                s = plot.getData()[s];
            }

            if (typeof point === "number") {
                var ps = s.datapoints.pointsize;
                point = s.datapoints.points.slice(ps * point, ps * (point + 1));
            }

            var i = indexOfHighlight(s, point);
            if (i !== -1) {
                highlights.splice(i, 1);

                plot.triggerRedrawOverlay();
            }
        }

        function indexOfHighlight(s, p) {
            for (var i = 0; i < highlights.length; ++i) {
                var h = highlights[i];
                if (h.series === s &&
                    h.point[0] === p[0] &&
                    h.point[1] === p[1]) {
                    return i;
                }
            }

            return -1;
        }

        function processRawData() {
            triggerCleanupEvent();
            doTriggerClickHoverEvent(lastMouseMoveEvent, eventType.hover);
        }

        function drawOverlay(plot, octx, overlay) {
            var plotOffset = plot.getPlotOffset(),
                i, hi;

            octx.save();
            octx.translate(plotOffset.left, plotOffset.top);
            for (i = 0; i < highlights.length; ++i) {
                hi = highlights[i];

                if (hi.series.bars.show) drawBarHighlight(hi.series, hi.point, octx);
                else drawPointHighlight(hi.series, hi.point, octx, plot);
            }
            octx.restore();
        }

        function drawPointHighlight(series, point, octx, plot) {
            var x = point[0],
                y = point[1],
                axisx = series.xaxis,
                axisy = series.yaxis,
                highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString();

            if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) {
                return;
            }

            var pointRadius = series.points.radius + series.points.lineWidth / 2;
            octx.lineWidth = pointRadius;
            octx.strokeStyle = highlightColor;
            var radius = 1.5 * pointRadius;
            x = axisx.p2c(x);
            y = axisy.p2c(y);

            octx.beginPath();
            var symbol = series.points.symbol;
            if (symbol === 'circle') {
                octx.arc(x, y, radius, 0, 2 * Math.PI, false);
            } else if (typeof symbol === 'string' && plot.drawSymbol && plot.drawSymbol[symbol]) {
                plot.drawSymbol[symbol](octx, x, y, radius, false);
            }

            octx.closePath();
            octx.stroke();
        }

        function drawBarHighlight(series, point, octx) {
            var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(),
                fillStyle = highlightColor,
                barLeft;

            var barWidth = series.bars.barWidth[0] || series.bars.barWidth;
            switch (series.bars.align) {
                case "left":
                    barLeft = 0;
                    break;
                case "right":
                    barLeft = -barWidth;
                    break;
                default:
                    barLeft = -barWidth / 2;
            }

            octx.lineWidth = series.bars.lineWidth;
            octx.strokeStyle = highlightColor;

            var fillTowards = series.bars.fillTowards || 0,
                bottom = fillTowards > series.yaxis.min ? Math.min(series.yaxis.max, fillTowards) : series.yaxis.min;

            $.plot.drawSeries.drawBar(point[0], point[1], point[2] || bottom, barLeft, barLeft + barWidth,
                function() {
                    return fillStyle;
                }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
        }

        function initHover(plot, options) {
            plot.highlight = highlight;
            plot.unhighlight = unhighlight;
            if (options.grid.hoverable || options.grid.clickable) {
                plot.hooks.drawOverlay.push(drawOverlay);
                plot.hooks.processRawData.push(processRawData);
            }

            lastMouseMoveEvent = plot.getPlaceholder()[0].lastMouseMoveEvent;
        }

        plot.hooks.bindEvents.push(bindEvents);
        plot.hooks.shutdown.push(shutdown);
        plot.hooks.processOptions.push(initHover);
    }

    $.plot.plugins.push({
        init: init,
        options: options,
        name: 'hover',
        version: '0.1'
    });
})(jQuery);
<|endoftext|>


<commit_before>describe('homeController', function() {
  beforeEach(module('primed'));

  var $controller;

  beforeEach(inject(function(_$controller_){
    // The injector unwraps the underscores (_) from around the parameter names when matching
    $controller = _$controller_;
  }));

    describe('$scope.city', function() {
      it('sets the app city being searched to what is passed to $scope.city', function() {
          var $scope = {};
          var controller = $controller('homeController', { $scope: $scope });
          $scope.city = 'Miami';
          $scope.$watch();
          expect(cityService.city).toEqual('Miami');
        });
    });

    describe('$scope.theme', function() {
        it('sets the app theme to what is passed into the $scope.theme ', function() {
            var $scope = {};
            var controller = $controller('homeController', { $scope: $scope });
            $scope.theme = 'party';
            $scope.$watch();
            expect(gifService.theme).toEqual('party');
        });
    });

     describe('$scope.submit', function() {
        it('Submit will take the user to the forecast page', function() {
            var $scope = {};
            var controller = $controller('homeController', { $scope: $scope, $location });
            $scope.submit();
            expect($location.path).toEqual('/forecast');
        });
     });
});<commit_msg>testing forecastController<commit_after>describe('homeController', function() {
  beforeEach(module('primed'));

  var $controller;

  beforeEach(inject(function(_$controller_){
    // The injector unwraps the underscores (_) from around the parameter names when matching
    $controller = _$controller_;
  }));

    describe('$scope.city', function() {
      it('sets the app city being searched to what is passed to $scope.city', function() {
          var $scope = {};
          var controller = $controller('homeController', { $scope: $scope });
          $scope.city = 'Miami';
          $scope.$watch();
          expect(cityService.city).toEqual('Miami');
        });
    });

    describe('$scope.theme', function() {
        it('sets the app theme to what is passed into the $scope.theme ', function() {
            var $scope = {};
            var controller = $controller('homeController', { $scope: $scope });
            $scope.theme = 'party';
            $scope.$watch();
            expect(gifService.theme).toEqual('party');
        });
    });

     describe('$scope.submit', function() {
        it('Submit will take the user to the forecast page', function() {
            var $scope = {};
            var controller = $controller('homeController', { $scope: $scope });
            $scope.submit();
            expect($location.path).toEqual('/forecast');
        });
     });
});

describe('forecastController', function() {
  beforeEach(module('primed'));

  var $controller;

  beforeEach(inject(function(_$controller_){
    // The injector unwraps the underscores (_) from around the parameter names when matching
    $controller = _$controller_;
  }));

    describe('$scope.city', function() {
      it('', function() {
          var $scope = {city: null, days: null, theme: null};
          var controller = $controller('forecastController', { $scope: $scope });
          expect($scope.city).toEqual('denver, CO');
          expect($scope.days).toEqual('3');
          expect($scope.theme).toEqual('seinfeld');
        });
    });

});<|endoftext|>


<commit_before>import React from 'react';
import ReactFauxDOM from 'react-faux-dom';
import d3 from 'd3';
import sankey from 'd3-plugins-sankey';
import _ from 'lodash';

export default class extends React.Component {
  constructor() {
    super()

    this.state = {
      nodes: [],
      links: []
    };
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      nodes: nextProps.nodes,
      links: nextProps.links
    });
  }

  render() {
    // ========================================================================
    // Set units, margin, sizes
    // ========================================================================
    var margin = { top: 10, right: 0, bottom: 10, left: 0 };
    var width = 690 - margin.left - margin.right;
    var height = 400 - margin.top - margin.bottom;

    var format = (d) => formatNumber(d);
    var formatNumber = d3.format(",.0f"); // zero decimal places

    // ========================================================================
    // Initialize and append the svg canvas to faux-DOM
    // ========================================================================
    var svgNode = ReactFauxDOM.createElement('div');

    var svg = d3.select(svgNode).append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    // ========================================================================
    // Set the sankey diagram properties
    // ========================================================================
    var sankey = d3.sankey()
        .size([width, height])
        .nodeWidth(15)
        .nodePadding(10);

    var path = sankey.link();

    var graph = {
      nodes: _.cloneDeep(this.state.nodes),
      links: _.cloneDeep(this.state.links)
    };

    sankey.nodes(graph.nodes)
        .links(graph.links)
        .layout(32);

    // ========================================================================
    // Add links
    // ========================================================================
    var link = svg.append("g").selectAll(".link")
        .data(graph.links)
        .enter().append("path")
        .attr("class", "link")
        .on('click', this.props.openModal) // register eventListener
        .attr("d", path)
        .style("stroke-width", (d) => Math.max(1, d.dy))

    // add link titles
    link.append("title")
        .text((d) => d.source.name + " → " + d.target.name + "\n Weight: " + format(d.value));

    // ========================================================================
    // Add nodes
    // ========================================================================
    var node = svg.append("g").selectAll(".node")
        .data(graph.nodes)
        .enter().append("g")
        .attr("class", "node")
        .on('click', this.props.openModal) // register eventListener
        .attr("transform", (d) => "translate(" + d.x + "," + d.y + ")")

    // add nodes rect
    node.append("rect")
        .attr("height", (d) => d.dy)
        .attr("width", sankey.nodeWidth())
        .append("title")
        .text((d) => d.name + "\n" + format(d.value));

    // add nodes text
    node.append("text")
        .attr("x", -6)
        .attr("y", (d) => d.dy / 2)
        .attr("dy", ".35em")
        .attr("text-anchor", "end")
        .text((d) => d.name)
        .filter((d) => d.x < width / 2)
        .attr("x", 6 + sankey.nodeWidth())
        .attr("text-anchor", "start");

    // ========================================================================
    // Render the faux-DOM to React elements
    // ========================================================================
    return svgNode.toReact()
  }
}
<commit_msg>added jsx-d3 equivalent<commit_after>import React from 'react';
import ReactFauxDOM from 'react-faux-dom';
import d3 from 'd3';
import sankey from 'd3-plugins-sankey';
import _ from 'lodash';

export default class extends React.Component {
  constructor() {
    super()

    this.state = {
      nodes: [],
      links: []
    };
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      nodes: nextProps.nodes,
      links: nextProps.links
    });
  }

  render() {
    // ========================================================================
    // Set units, margin, sizes
    // ========================================================================
    var margin = { top: 10, right: 0, bottom: 10, left: 0 };
    var width = 690 - margin.left - margin.right;
    var height = 400 - margin.top - margin.bottom;

    var format = (d) => formatNumber(d);
    var formatNumber = d3.format(",.0f"); // zero decimal places

    // ========================================================================
    // Initialize and append the svg canvas to faux-DOM
    // ========================================================================
    var svgNode = ReactFauxDOM.createElement('div');

    var svg = d3.select(svgNode).append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    // ========================================================================
    // Set the sankey diagram properties
    // ========================================================================
    var sankey = d3.sankey()
        .size([width, height])
        .nodeWidth(15)
        .nodePadding(10);

    var path = sankey.link();

    var graph = {
      nodes: _.cloneDeep(this.state.nodes),
      links: _.cloneDeep(this.state.links)
    };

    sankey.nodes(graph.nodes)
        .links(graph.links)
        .layout(32);

    // ========================================================================
    // Add links
    // ========================================================================
    var link = svg.append("g").selectAll(".link")
      .data(graph.links)
      .enter().append("path")
      .attr("class", "link")
      .on('click', this.props.openModal) // register eventListener
      .attr("d", path)
      .style("stroke-width", (d) => Math.max(1, d.dy))

    // add link titles
    link.append("title")
      .text((d) => d.source.name + " → " + d.target.name + "\n Weight: " + format(d.value));

    // ========================================================================
    // Add nodes
    // ========================================================================
    var node = svg.append("g").selectAll(".node")
      .data(graph.nodes)
      .enter().append("g")
      .attr("class", "node")
      .on('click', this.props.openModal) // register eventListener
      .attr("transform", (d) => "translate(" + d.x + "," + d.y + ")")

    // add nodes rect
    node.append("rect")
      .attr("height", (d) => d.dy)
      .attr("width", sankey.nodeWidth())
      .append("title")
      .text((d) => d.name + "\n" + format(d.value));

    // add nodes text
    node.append("text")
      .attr("x", -6)
      .attr("y", (d) => d.dy / 2)
      .attr("dy", ".35em")
      .attr("text-anchor", "end")
      .text((d) => d.name)
      .filter((d) => d.x < width / 2)
      .attr("x", 6 + sankey.nodeWidth())
      .attr("text-anchor", "start");

    // Above D3 manipaluation equal to following jsx if didn't rely on faux-dom
    // ------------------------------------------------------------------------
    // var links = graph.links.map((link) => {
    //   <path className="link" onClick={this.props.openModal} d={path} style={"stroke-width", Math.max(1, link.dy)}>
    //     <title>{link.source.name + " → " + link.target.name + "\n Weight: " + format(link.value)}</title>
    //   </path>
    // });

    // var nodes - graph.nodes.map((node) => {
    //   <g className="node" onClick={this.props.openModal} transform={"translate(" + node.x + "," + node.y + ")"}>
    //     <rect height={node.dy} width={sankey.nodeWidth()}>
    //       <title>{node.name + "\n" + format(d.value)}</title>
    //     </rect>
    //     { (node.x >= width / 2) ?
    //       <text x={-6} y={node.dy / 2} dy={".35em"} textAnchor={"end"} >{node.name}</text> :
    //       <text x={6 + sankey.nodeWidth()} y={node.dy / 2} dy={".35em"} textAnchor={"start"} >{node.name}</text>
    //     }
    //   </g>
    // });

    // <svg width={width + margin.left + margin.right} height={height + margin.top + margin.bottom}>
    //   <g transform={"translate(" + margin.left + "," + margin.top + ")"}>
    //     {links}
    //   </g>
    //   <g>
    //    {links}
    //   </g>
    // </svg>

    // ========================================================================
    // Render the faux-DOM to React elements
    // ========================================================================
    return svgNode.toReact()
  }
}
<|endoftext|>


<commit_before>const GovPay = require('../lib/helper');
const request = require('request');
const EmailService =require('./../lib/EmailService')

module.exports = function(router, configGovPay, app) {

    // =====================================
    // SESSION EXPIRED
    // =====================================
    router

        // healthcheck
        .get('/session-expired', function(req, res) {
            let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl;
            return res.render('session-expired', {
                startNewApplicationUrl:startNewApplicationUrl
            })
        });

    // =====================================
    // HEALTHCHECK
    // =====================================
    router

        // healthcheck
        .get('/healthcheck', function(req, res) {
            res.json({message: 'Payment Service is running'});
        });

    // =====================================
    // ERROR - PAYMENTS
    // =====================================
    router

        //error handling
        .get('/payment-error', function(req,res) {
            let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl;
            return res.render('payment-error', {
                errorMessage:'',
                startNewApplicationUrl:startNewApplicationUrl
            })
        });

    // =====================================
    // ERROR - ADDITIONAL PAYMENTS
    // =====================================
    router

        //error handling
        .get('/additional-payment-error', function(req,res) {
            let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl + '/additional-payments';
            return res.render('additional-payment-error', {
                errorMessage:'',
                startNewApplicationUrl:startNewApplicationUrl
            })
        });

    // ===============================
    // ADDITIONAL PAYMENTS
    // ===============================
    router
        // process additional payments
        .post('/submit-additional-payment', function (req, res) {
            submitAdditionalPayment(req, res)
        });

    function submitAdditionalPayment(req,res){

        let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl + '/additional-payments';

        try {
            let moment = require('moment');
            let sess = req.session
            let casebookRef = sess.additionalPayments.casebookRef

            // build required data
            let formFields = {};
            formFields = GovPay.additionalPaymentsAddBaseData(formFields, casebookRef, sess.additionalPayments.cost, sess.additionalPayments.email);

            request.post({
                headers: {
                    "content-type": "application/json; charset=utf-8",
                    "Authorization": "Bearer " + configGovPay.configs.ukPayApiKey
                },
                url: configGovPay.configs.ukPayUrl,
                body: JSON.stringify(formFields)
            }, function (error, response) {
                if (error) {
                    console.log(JSON.stringify(error));
                } else {
                    let returnData = JSON.parse(response.body)
                    let next_url = returnData._links.next_url.href
                    sess.additionalPayments.paymentReference = returnData.payment_id

                    if (casebookRef) {
                        let AdditionalPaymentDetails = require('../models/index').AdditionalPaymentDetails;
                        AdditionalPaymentDetails.find({
                            where: {
                                application_id: returnData.reference
                            }
                        }).then( function(additionalPayment) {
                            if (!additionalPayment) {
                                AdditionalPaymentDetails.create({
                                    application_id: returnData.reference,
                                    payment_reference: returnData.payment_id,
                                    payment_amount: returnData.amount / 100,
                                    payment_status: returnData.state.status,
                                    payment_complete: false,
                                    created_at: moment(returnData.created_date).format('DD MMMM YYYY, h:mm:ss A'),
                                    submitted: 'draft'
                                })
                            }
                        })
                    }

                    res.render('additionalPayments/submit-additional-payment', {
                        cost:sess.additionalPayments.cost,
                        next_url: next_url,
                        startNewApplicationUrl:startNewApplicationUrl
                    })

                }

            })

        } catch (err) {
            console.log(err);
            return res.render('additional-payment-error', {
                errorMessage:err,
                startNewApplicationUrl:startNewApplicationUrl
            })
        }
    }

    router
        // additional payment confirmation on return from Gov Pay
        .get('/additional-payment-confirmation', function(req, res) {
            processAdditionalPayment(req,res)
        });

    function processAdditionalPayment(req,res){

        try {
            let moment = require('moment')
            let sess = req.session
            let isSessionValid = (typeof sess.additionalPayments.cost !== 'undefined');
            let payment_id = sess.additionalPayments.paymentReference
            let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl + '/additional-payments';

            request.get({
                headers: {
                    "Authorization": "Bearer " + configGovPay.configs.ukPayApiKey
                },
                url: configGovPay.configs.ukPayUrl + payment_id,
            }, function (error, response, body) {
                if (error) {
                    let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl + '/additional-payments';
                    console.log(error);
                    return res.render('additional-payment-error', {
                        errorMessage:'Payment system error',
                        startNewApplicationUrl:startNewApplicationUrl
                    })
                }
                let returnData = JSON.parse(body)
                let cost = returnData.amount / 100
                let status = returnData.state.status
                let finished = returnData.state.finished
                let appReference = returnData.reference
                let paymentMethod = returnData.card_details.card_brand
                let createdDate = moment(returnData.created_date).format('DD MMMM YYYY, h:mm:ss A')

                if (status && status === 'success' && finished && finished === true){

                    console.log(payment_id + ' - payment is successful');

                    if (isSessionValid) {

                        EmailService.additionalPaymentReceipt(
                            sess.additionalPayments.email,
                            createdDate,
                            appReference,
                            'Get Document Legalised – Additional Payments',
                            sess.additionalPayments.cost,
                            paymentMethod
                        )

                        let casebookRef = sess.additionalPayments.casebookRef
                        if (casebookRef) {
                            let AdditionalPaymentDetails = require('../models/index').AdditionalPaymentDetails;
                            AdditionalPaymentDetails.update({
                                payment_status: 'AUTHORISED',
                                payment_reference: payment_id,
                                payment_amount: cost,
                                payment_complete: true,
                                updated_at: moment().format('DD MMMM YYYY, h:mm:ss A'),
                                submitted: 'queued'
                            }, {
                                where:{
                                    application_id: returnData.reference
                                }
                            })
                        }
                    }

                    res.render('additionalPayments/additional-payment-confirmation', {
                        req:req,
                        isSessionValid:isSessionValid,
                        paymentSuccessful:true,
                        appReference:appReference,
                        createdDate:createdDate,
                        paymentMethod:paymentMethod,
                        cost:sess.additionalPayments.cost,
                        email:sess.additionalPayments.email,
                        startNewApplicationUrl:startNewApplicationUrl
                    });

                } else {

                    console.log(payment_id + ' - payment is NOT successful');
                    let formFields = {};
                    formFields = GovPay.additionalPaymentsAddBaseData(formFields, sess.additionalPayments.casebookRef, sess.additionalPayments.cost, sess.additionalPayments.email);

                    request.post({
                        headers: {
                            "content-type": "application/json; charset=utf-8",
                            "Authorization": "Bearer " + configGovPay.configs.ukPayApiKey
                        },
                        url: configGovPay.configs.ukPayUrl,
                        body: JSON.stringify(formFields)
                    }, function (error, response) {
                        if (error) {
                            console.log(JSON.stringify(error));
                        } else {
                            var returnData = JSON.parse(response.body)
                            var next_url = returnData._links.next_url.href
                            sess.additionalPayments.paymentReference = returnData.payment_id

                            res.render('additionalPayments/additional-payment-confirmation', {
                                isSessionValid:isSessionValid,
                                paymentSuccessful:false,
                                cost:sess.cost,
                                next_url: next_url,
                                startNewApplicationUrl:startNewApplicationUrl
                            });

                        }

                    })

                }

        })

        }catch (err) {
            let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl + '/additional-payments';
            console.log(err);
            return res.render('additional-payment-error', {
                errorMessage:err,
                startNewApplicationUrl:startNewApplicationUrl
            })
        }
    }

    // =====================================
    // SEND PAYMENT
    // =====================================
    router
        // redirect to Gov Pay to process payment
        .get('/submit-payment', function(req,res){submitPayment(req,res);})
        .post('/submit-payment', function(req,res){submitPayment(req,res);});

    function submitPayment(req,res){

        // get the application ID from the request (redirected from application service)
        var appid = req.session.appId;
        if( req.session.appId && req.session.appId !==0 ){
            //Do nothing
        }
        else{

            res.clearCookie('LoggedIn');
            req.session.appId = false;
            var startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl;
            return res.render('payment-error', {
                errorMessage:'Missing user session',
                startNewApplicationUrl:startNewApplicationUrl
            })
        }
        var loggedIn = GovPay.loggedInStatus(req);
        var usersEmail = (loggedIn) ? GovPay.loggedInUserEmail(req) : GovPay.loggedOutUserEmail(req)

        // get the relevant database models
        var ApplicationPaymentDetails = require('../models/index').ApplicationPaymentDetails;
        var Application = require('../models/index').Application;
        var UserDetails = require('../models/index').UserDetails;
        var UserDocumentCount = require('../models/index').UserDocumentCount;

        // lookup required data from database
        Application.findOne({ where: {application_id: appid}}).then(function(application){

            ApplicationPaymentDetails.findOne({ where: {application_id: appid }}).then(function(applicationDetail){

                UserDetails.findOne({ where: {application_id: appid}}).then(function(userDetails){

                    UserDocumentCount.findOne({ where: {application_id: appid}}).then(function(userDocumentCount) {

                        // array to hold data for sending to Payment API
                        var formFields = {};

                        formFields = GovPay.buildUkPayData(formFields, applicationDetail, application, usersEmail);

                        request.post({
                            headers: {
                                "content-type": "application/json; charset=utf-8",
                                "Authorization": "Bearer " + configGovPay.configs.ukPayApiKey
                            },
                            url: configGovPay.configs.ukPayUrl,
                            body: JSON.stringify(formFields)
                        }, function (error, response) {
                            if (error) {
                                console.log(JSON.stringify(error));
                            } else {
                                var returnData = JSON.parse(response.body)
                                var next_url = returnData._links.next_url.href

                                // update database (add payment reference)
                                ApplicationPaymentDetails.update({
                                    payment_reference : returnData.payment_id
                                },{
                                    where: {
                                        application_id: appid
                                    }
                                }).then( function() {
                                    //redirect to next form page with parameters
                                    res.render('submit-payment.ejs', {
                                        applicationId: appid,
                                        applicationType: application.serviceType,
                                        loggedIn: loggedIn,
                                        usersEmail: usersEmail,
                                        next_url: next_url,
                                        startNewApplicationUrl:startNewApplicationUrl,
                                        user_data: {
                                            loggedIn: req.session && req.session.passport && req.session.passport.user,
                                            user: req.session.user,
                                            account: req.session.account,
                                            url: '/api/user/'
                                        }
                                    });

                                }).catch(function (error) {
                                    console.log(appId + ' - ' + error);
                                });

                            }

                        })

                    });
                });
            });
        });
    }

    // =====================================
    // PAYMENT CONFIRMATION
    // =====================================

    router

        // prepare confirmation page
        .get('/payment-confirmation', function(req, res) {

            // get appId from the session
            // else send user to error page
            var appId = req.session.appId;
            if (req.session.appId && req.session.appId !==0) {
                //Do nothing
            }
            else{
                res.clearCookie('LoggedIn');
                req.session.appId = false;
                var startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl;
                return res.render('payment-error', {
                    errorMessage:'Missing user session',
                    startNewApplicationUrl:startNewApplicationUrl
                })
            }

            // get the relevant database models
            var ApplicationPaymentDetails = require('../models/index').ApplicationPaymentDetails;
            var Application = require('../models/index').Application;
            var UserDetails = require('../models/index').UserDetails;
            var UserDocumentCount = require('../models/index').UserDocumentCount;

            // check the payment id from the database
            ApplicationPaymentDetails.findOne({
                    where: {
                        application_id: appId
                    }
                }
            ).then(function (results) {
                var payment_id = results.payment_reference

                request.get({
                    headers: {
                        "Authorization": "Bearer " + configGovPay.configs.ukPayApiKey
                    },
                    url: configGovPay.configs.ukPayUrl + payment_id,
                }, function (error, response, body) {
                    if (error) {
                        console.log(appId + ' - ' + error);
                        let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl;
                        return res.render('payment-error', {
                            errorMessage:'Payment system error',
                            startNewApplicationUrl:startNewApplicationUrl
                        })
                    }
                    var returnData = JSON.parse(body)
                    var status = returnData.state.status
                    var finished = returnData.state.finished
                    var appReference = returnData.reference

                    if (status && status === 'success' && finished && finished === true){

                        ApplicationPaymentDetails.update({
                            payment_complete: true,
                            payment_status: 'AUTHORISED'
                        }, {
                            where: {
                                application_id: appId
                            }
                        }).then(function() {
                            console.log(appId + ' - payment is successful');
                            res.redirect(configGovPay.configs.applicationServiceReturnUrl + '?id=' + appId + '&appReference=' + appReference);
                        }).catch(function (error) {
                            console.log(appId + ' - ' + error);
                        });

                    } else {

                        console.log(appId + ' - payment is NOT successful');
                        var loggedIn = GovPay.loggedInStatus(req);
                        var usersEmail = (loggedIn) ? GovPay.loggedInUserEmail(req) : GovPay.loggedOutUserEmail(req)
                        var isSessionValid = GovPay.isSessionValid(req);

                                // lookup required data from database
                                var formFieldsTemp = Application.findOne({ where: {application_id: appId}}).then(function(application) {

                                    ApplicationPaymentDetails.findOne({where: {application_id: appId}}).then(function (applicationDetail) {

                                        UserDetails.findOne({where: {application_id: appId}}).then(function (userDetails) {

                                            UserDocumentCount.findOne({where: {application_id: appId}}).then(function (userDocumentCount) {

                                                // array to hold data for sending to Payment API
                                                var formFields = {};

                                                formFields = GovPay.buildUkPayData(formFields, applicationDetail, application, usersEmail);

                                                request.post({
                                                    headers: {
                                                        "content-type": "application/json; charset=utf-8",
                                                        "Authorization": "Bearer " + configGovPay.configs.ukPayApiKey
                                                    },
                                                    url: configGovPay.configs.ukPayUrl,
                                                    body: JSON.stringify(formFields)
                                                }, function (error, response) {
                                                    if (error) {
                                                        console.log(JSON.stringify(error));
                                                    } else {
                                                        var returnData = JSON.parse(response.body)
                                                        var next_url = returnData._links.next_url.href

                                                        // update database (add payment reference)
                                                        ApplicationPaymentDetails.update({
                                                            payment_reference : returnData.payment_id
                                                        },{
                                                            where: {
                                                                application_id: appId
                                                            }
                                                        }).then( function() {
                                                            console.log(appId + ' - rendering failed payment page');
                                                            // display failed payment page (with link to start a new payment)

                                                            res.render('payment-confirmation.ejs',
                                                                {
                                                                    applicationId: appId,
                                                                    applicationType: application.serviceType,
                                                                    next_url: next_url,
                                                                    startNewApplicationUrl: configGovPay.configs.startNewApplicationUrl,
                                                                    loggedIn: loggedIn,
                                                                    isSessionValid: isSessionValid,
                                                                    usersEmail: usersEmail,
                                                                    user_data: {
                                                                        loggedIn: req.session && req.session.passport && req.session.passport.user,
                                                                        user: req.session.user,
                                                                        account: req.session.account,
                                                                        url: '/api/user/'
                                                                    }
                                                                });

                                                        }).catch(function (error) {
                                                            console.log(appId + ' - ' + error);
                                                        });

                                                    }

                                                })

                                            }).catch(function (error) {
                                                console.log(appId + ' - ' + error);
                                            });
                                        }).catch(function (error) {
                                            console.log(appId + ' - ' + error);
                                        });
                                    }).catch(function (error) {
                                        console.log(appId + ' - ' + error);
                                    });
                                }).catch(function (error) {
                                    console.log(appId + ' - ' + error);
                                });

                    }
                });

            }).catch(function (error) {
                console.log(appId + ' - ' + error);
            });

        });
};

<commit_msg>Fix bug with Additional Payments<commit_after>const GovPay = require('../lib/helper');
const request = require('request');
const EmailService =require('./../lib/EmailService')

module.exports = function(router, configGovPay, app) {

    // =====================================
    // SESSION EXPIRED
    // =====================================
    router

        // healthcheck
        .get('/session-expired', function(req, res) {
            let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl;
            return res.render('session-expired', {
                startNewApplicationUrl:startNewApplicationUrl
            })
        });

    // =====================================
    // HEALTHCHECK
    // =====================================
    router

        // healthcheck
        .get('/healthcheck', function(req, res) {
            res.json({message: 'Payment Service is running'});
        });

    // =====================================
    // ERROR - PAYMENTS
    // =====================================
    router

        //error handling
        .get('/payment-error', function(req,res) {
            let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl;
            return res.render('payment-error', {
                errorMessage:'',
                startNewApplicationUrl:startNewApplicationUrl
            })
        });

    // =====================================
    // ERROR - ADDITIONAL PAYMENTS
    // =====================================
    router

        //error handling
        .get('/additional-payment-error', function(req,res) {
            let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl + '/additional-payments';
            return res.render('additional-payment-error', {
                errorMessage:'',
                startNewApplicationUrl:startNewApplicationUrl
            })
        });

    // ===============================
    // ADDITIONAL PAYMENTS
    // ===============================
    router
        // process additional payments
        .post('/submit-additional-payment', function (req, res) {
            submitAdditionalPayment(req, res)
        });

    function submitAdditionalPayment(req,res){

        let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl + '/additional-payments';

        try {
            let moment = require('moment');
            let sess = req.session
            let casebookRef = sess.additionalPayments.casebookRef

            // build required data
            let formFields = {};
            formFields = GovPay.additionalPaymentsAddBaseData(formFields, casebookRef, sess.additionalPayments.cost, sess.additionalPayments.email);

            request.post({
                headers: {
                    "content-type": "application/json; charset=utf-8",
                    "Authorization": "Bearer " + configGovPay.configs.ukPayApiKey
                },
                url: configGovPay.configs.ukPayUrl,
                body: JSON.stringify(formFields)
            }, function (error, response) {
                if (error) {
                    console.log(JSON.stringify(error));
                } else {
                    let returnData = JSON.parse(response.body)
                    let next_url = returnData._links.next_url.href
                    sess.additionalPayments.paymentReference = returnData.payment_id

                    if (casebookRef) {
                        let AdditionalPaymentDetails = require('../models/index').AdditionalPaymentDetails;
                        AdditionalPaymentDetails.findOne({
                            where: {
                                application_id: returnData.reference
                            }
                        }).then( function(additionalPayment) {
                            if (!additionalPayment) {
                                AdditionalPaymentDetails.create({
                                    application_id: returnData.reference,
                                    payment_reference: returnData.payment_id,
                                    payment_amount: returnData.amount / 100,
                                    payment_status: returnData.state.status,
                                    payment_complete: false,
                                    created_at: moment(returnData.created_date).format('DD MMMM YYYY, h:mm:ss A'),
                                    submitted: 'draft'
                                })
                            }
                        })
                    }

                    res.render('additionalPayments/submit-additional-payment', {
                        cost:sess.additionalPayments.cost,
                        next_url: next_url,
                        startNewApplicationUrl:startNewApplicationUrl
                    })

                }

            })

        } catch (err) {
            console.log(err);
            return res.render('additional-payment-error', {
                errorMessage:err,
                startNewApplicationUrl:startNewApplicationUrl
            })
        }
    }

    router
        // additional payment confirmation on return from Gov Pay
        .get('/additional-payment-confirmation', function(req, res) {
            processAdditionalPayment(req,res)
        });

    function processAdditionalPayment(req,res){

        try {
            let moment = require('moment')
            let sess = req.session
            let isSessionValid = (typeof sess.additionalPayments.cost !== 'undefined');
            let payment_id = sess.additionalPayments.paymentReference
            let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl + '/additional-payments';

            request.get({
                headers: {
                    "Authorization": "Bearer " + configGovPay.configs.ukPayApiKey
                },
                url: configGovPay.configs.ukPayUrl + payment_id,
            }, function (error, response, body) {
                if (error) {
                    let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl + '/additional-payments';
                    console.log(error);
                    return res.render('additional-payment-error', {
                        errorMessage:'Payment system error',
                        startNewApplicationUrl:startNewApplicationUrl
                    })
                }
                let returnData = JSON.parse(body)
                let cost = returnData.amount / 100
                let status = returnData.state.status
                let finished = returnData.state.finished
                let appReference = returnData.reference
                let paymentMethod = returnData.card_details.card_brand
                let createdDate = moment(returnData.created_date).format('DD MMMM YYYY, h:mm:ss A')

                if (status && status === 'success' && finished && finished === true){

                    console.log(payment_id + ' - payment is successful');

                    if (isSessionValid) {

                        EmailService.additionalPaymentReceipt(
                            sess.additionalPayments.email,
                            createdDate,
                            appReference,
                            'Get Document Legalised – Additional Payments',
                            sess.additionalPayments.cost,
                            paymentMethod
                        )

                        let casebookRef = sess.additionalPayments.casebookRef
                        if (casebookRef) {
                            let AdditionalPaymentDetails = require('../models/index').AdditionalPaymentDetails;
                            AdditionalPaymentDetails.update({
                                payment_status: 'AUTHORISED',
                                payment_reference: payment_id,
                                payment_amount: cost,
                                payment_complete: true,
                                updated_at: moment().format('DD MMMM YYYY, h:mm:ss A'),
                                submitted: 'queued'
                            }, {
                                where:{
                                    application_id: returnData.reference
                                }
                            })
                        }
                    }

                    res.render('additionalPayments/additional-payment-confirmation', {
                        req:req,
                        isSessionValid:isSessionValid,
                        paymentSuccessful:true,
                        appReference:appReference,
                        createdDate:createdDate,
                        paymentMethod:paymentMethod,
                        cost:sess.additionalPayments.cost,
                        email:sess.additionalPayments.email,
                        startNewApplicationUrl:startNewApplicationUrl
                    });

                } else {

                    console.log(payment_id + ' - payment is NOT successful');
                    let formFields = {};
                    formFields = GovPay.additionalPaymentsAddBaseData(formFields, sess.additionalPayments.casebookRef, sess.additionalPayments.cost, sess.additionalPayments.email);

                    request.post({
                        headers: {
                            "content-type": "application/json; charset=utf-8",
                            "Authorization": "Bearer " + configGovPay.configs.ukPayApiKey
                        },
                        url: configGovPay.configs.ukPayUrl,
                        body: JSON.stringify(formFields)
                    }, function (error, response) {
                        if (error) {
                            console.log(JSON.stringify(error));
                        } else {
                            var returnData = JSON.parse(response.body)
                            var next_url = returnData._links.next_url.href
                            sess.additionalPayments.paymentReference = returnData.payment_id

                            res.render('additionalPayments/additional-payment-confirmation', {
                                isSessionValid:isSessionValid,
                                paymentSuccessful:false,
                                cost:sess.cost,
                                next_url: next_url,
                                startNewApplicationUrl:startNewApplicationUrl
                            });

                        }

                    })

                }

        })

        }catch (err) {
            let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl + '/additional-payments';
            console.log(err);
            return res.render('additional-payment-error', {
                errorMessage:err,
                startNewApplicationUrl:startNewApplicationUrl
            })
        }
    }

    // =====================================
    // SEND PAYMENT
    // =====================================
    router
        // redirect to Gov Pay to process payment
        .get('/submit-payment', function(req,res){submitPayment(req,res);})
        .post('/submit-payment', function(req,res){submitPayment(req,res);});

    function submitPayment(req,res){

        // get the application ID from the request (redirected from application service)
        var appid = req.session.appId;
        if( req.session.appId && req.session.appId !==0 ){
            //Do nothing
        }
        else{

            res.clearCookie('LoggedIn');
            req.session.appId = false;
            var startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl;
            return res.render('payment-error', {
                errorMessage:'Missing user session',
                startNewApplicationUrl:startNewApplicationUrl
            })
        }
        var loggedIn = GovPay.loggedInStatus(req);
        var usersEmail = (loggedIn) ? GovPay.loggedInUserEmail(req) : GovPay.loggedOutUserEmail(req)

        // get the relevant database models
        var ApplicationPaymentDetails = require('../models/index').ApplicationPaymentDetails;
        var Application = require('../models/index').Application;
        var UserDetails = require('../models/index').UserDetails;
        var UserDocumentCount = require('../models/index').UserDocumentCount;

        // lookup required data from database
        Application.findOne({ where: {application_id: appid}}).then(function(application){

            ApplicationPaymentDetails.findOne({ where: {application_id: appid }}).then(function(applicationDetail){

                UserDetails.findOne({ where: {application_id: appid}}).then(function(userDetails){

                    UserDocumentCount.findOne({ where: {application_id: appid}}).then(function(userDocumentCount) {

                        // array to hold data for sending to Payment API
                        var formFields = {};

                        formFields = GovPay.buildUkPayData(formFields, applicationDetail, application, usersEmail);

                        request.post({
                            headers: {
                                "content-type": "application/json; charset=utf-8",
                                "Authorization": "Bearer " + configGovPay.configs.ukPayApiKey
                            },
                            url: configGovPay.configs.ukPayUrl,
                            body: JSON.stringify(formFields)
                        }, function (error, response) {
                            if (error) {
                                console.log(JSON.stringify(error));
                            } else {
                                var returnData = JSON.parse(response.body)
                                var next_url = returnData._links.next_url.href

                                // update database (add payment reference)
                                ApplicationPaymentDetails.update({
                                    payment_reference : returnData.payment_id
                                },{
                                    where: {
                                        application_id: appid
                                    }
                                }).then( function() {
                                    //redirect to next form page with parameters
                                    res.render('submit-payment.ejs', {
                                        applicationId: appid,
                                        applicationType: application.serviceType,
                                        loggedIn: loggedIn,
                                        usersEmail: usersEmail,
                                        next_url: next_url,
                                        startNewApplicationUrl:startNewApplicationUrl,
                                        user_data: {
                                            loggedIn: req.session && req.session.passport && req.session.passport.user,
                                            user: req.session.user,
                                            account: req.session.account,
                                            url: '/api/user/'
                                        }
                                    });

                                }).catch(function (error) {
                                    console.log(appId + ' - ' + error);
                                });

                            }

                        })

                    });
                });
            });
        });
    }

    // =====================================
    // PAYMENT CONFIRMATION
    // =====================================

    router

        // prepare confirmation page
        .get('/payment-confirmation', function(req, res) {

            // get appId from the session
            // else send user to error page
            var appId = req.session.appId;
            if (req.session.appId && req.session.appId !==0) {
                //Do nothing
            }
            else{
                res.clearCookie('LoggedIn');
                req.session.appId = false;
                var startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl;
                return res.render('payment-error', {
                    errorMessage:'Missing user session',
                    startNewApplicationUrl:startNewApplicationUrl
                })
            }

            // get the relevant database models
            var ApplicationPaymentDetails = require('../models/index').ApplicationPaymentDetails;
            var Application = require('../models/index').Application;
            var UserDetails = require('../models/index').UserDetails;
            var UserDocumentCount = require('../models/index').UserDocumentCount;

            // check the payment id from the database
            ApplicationPaymentDetails.findOne({
                    where: {
                        application_id: appId
                    }
                }
            ).then(function (results) {
                var payment_id = results.payment_reference

                request.get({
                    headers: {
                        "Authorization": "Bearer " + configGovPay.configs.ukPayApiKey
                    },
                    url: configGovPay.configs.ukPayUrl + payment_id,
                }, function (error, response, body) {
                    if (error) {
                        console.log(appId + ' - ' + error);
                        let startNewApplicationUrl = configGovPay.configs.startNewApplicationUrl;
                        return res.render('payment-error', {
                            errorMessage:'Payment system error',
                            startNewApplicationUrl:startNewApplicationUrl
                        })
                    }
                    var returnData = JSON.parse(body)
                    var status = returnData.state.status
                    var finished = returnData.state.finished
                    var appReference = returnData.reference

                    if (status && status === 'success' && finished && finished === true){

                        ApplicationPaymentDetails.update({
                            payment_complete: true,
                            payment_status: 'AUTHORISED'
                        }, {
                            where: {
                                application_id: appId
                            }
                        }).then(function() {
                            console.log(appId + ' - payment is successful');
                            res.redirect(configGovPay.configs.applicationServiceReturnUrl + '?id=' + appId + '&appReference=' + appReference);
                        }).catch(function (error) {
                            console.log(appId + ' - ' + error);
                        });

                    } else {

                        console.log(appId + ' - payment is NOT successful');
                        var loggedIn = GovPay.loggedInStatus(req);
                        var usersEmail = (loggedIn) ? GovPay.loggedInUserEmail(req) : GovPay.loggedOutUserEmail(req)
                        var isSessionValid = GovPay.isSessionValid(req);

                                // lookup required data from database
                                var formFieldsTemp = Application.findOne({ where: {application_id: appId}}).then(function(application) {

                                    ApplicationPaymentDetails.findOne({where: {application_id: appId}}).then(function (applicationDetail) {

                                        UserDetails.findOne({where: {application_id: appId}}).then(function (userDetails) {

                                            UserDocumentCount.findOne({where: {application_id: appId}}).then(function (userDocumentCount) {

                                                // array to hold data for sending to Payment API
                                                var formFields = {};

                                                formFields = GovPay.buildUkPayData(formFields, applicationDetail, application, usersEmail);

                                                request.post({
                                                    headers: {
                                                        "content-type": "application/json; charset=utf-8",
                                                        "Authorization": "Bearer " + configGovPay.configs.ukPayApiKey
                                                    },
                                                    url: configGovPay.configs.ukPayUrl,
                                                    body: JSON.stringify(formFields)
                                                }, function (error, response) {
                                                    if (error) {
                                                        console.log(JSON.stringify(error));
                                                    } else {
                                                        var returnData = JSON.parse(response.body)
                                                        var next_url = returnData._links.next_url.href

                                                        // update database (add payment reference)
                                                        ApplicationPaymentDetails.update({
                                                            payment_reference : returnData.payment_id
                                                        },{
                                                            where: {
                                                                application_id: appId
                                                            }
                                                        }).then( function() {
                                                            console.log(appId + ' - rendering failed payment page');
                                                            // display failed payment page (with link to start a new payment)

                                                            res.render('payment-confirmation.ejs',
                                                                {
                                                                    applicationId: appId,
                                                                    applicationType: application.serviceType,
                                                                    next_url: next_url,
                                                                    startNewApplicationUrl: configGovPay.configs.startNewApplicationUrl,
                                                                    loggedIn: loggedIn,
                                                                    isSessionValid: isSessionValid,
                                                                    usersEmail: usersEmail,
                                                                    user_data: {
                                                                        loggedIn: req.session && req.session.passport && req.session.passport.user,
                                                                        user: req.session.user,
                                                                        account: req.session.account,
                                                                        url: '/api/user/'
                                                                    }
                                                                });

                                                        }).catch(function (error) {
                                                            console.log(appId + ' - ' + error);
                                                        });

                                                    }

                                                })

                                            }).catch(function (error) {
                                                console.log(appId + ' - ' + error);
                                            });
                                        }).catch(function (error) {
                                            console.log(appId + ' - ' + error);
                                        });
                                    }).catch(function (error) {
                                        console.log(appId + ' - ' + error);
                                    });
                                }).catch(function (error) {
                                    console.log(appId + ' - ' + error);
                                });

                    }
                });

            }).catch(function (error) {
                console.log(appId + ' - ' + error);
            });

        });
};

<|endoftext|>


<commit_before>
import expect from 'expect.js';
import { createStore, createAPI } from '../src/index';
import { emptyFunction } from './testUtils';

describe('Cartiv Store', () => {
  it('Cartiv index should expose createStore', () => {
    expect(createStore).to.be.a('function');
  });

  describe('handle dispatcher config', () => {
    it('should throw if proper api not provided', () => {
      expect(createStore).withArgs({ api: '' }, {}).to.throwError();
      expect(createStore).withArgs({ api: {} }, {}).to.throwError();
      expect(createStore).withArgs({ api: { a: 1 } }, {}).to.throwError();
      expect(createStore).withArgs({ api: [] }, {}).to.throwError();
      expect(createStore).withArgs({ api: () => {} }, {}).to.throwError();
    });

    it('should throw if proper name not provided', () => {
      expect(createStore).withArgs({ name: {} }, {}).to.throwError();
      expect(createStore).withArgs({ name: { a: 1 } }, {}).to.throwError();
      expect(createStore).withArgs({ name: [] }, {}).to.throwError();
      expect(createStore).withArgs({ name: () => {} }, {}).to.throwError();
    });

    it('should throw if proper actions not provided', () => {
      expect(createStore).withArgs({ actions: {} }, {}).to.throwError();
      expect(createStore).withArgs({ actions: { a: 1 } }, {}).to.throwError();
      expect(createStore).withArgs({ actions: [] }, {}).to.throwError();
      expect(createStore).withArgs({ actions: ['a', {}] }, {}).to.throwError();
    });
  });

  describe('handle store definition', () => {
    let api;
    let dispatcherConfig;
    beforeEach(() => {
      api = createAPI();
      dispatcherConfig = { api, name: 'name' };
    });

    it('should throw if not provided or not plain object', () => {
      expect(createStore).withArgs(dispatcherConfig, '').to.throwError();
      expect(createStore).withArgs(dispatcherConfig, () => {}).to.throwError();
      expect(createStore).withArgs(dispatcherConfig, []).to.throwError();
      expect(createStore).withArgs(dispatcherConfig, undefined).to.throwError();
      expect(createStore).withArgs(dispatcherConfig, null).to.throwError();
    });

    it('should throw if getInitialState is not a function', () => {
      expect(createStore).withArgs(dispatcherConfig, { getInitialState: [] }).to.throwError();
      expect(createStore).withArgs(dispatcherConfig, { getInitialState: {} }).to.throwError();
      expect(createStore).withArgs(dispatcherConfig, { getInitialState: '123' }).to.throwError();
    });
  });

  describe('created Store', () => {
    let api;
    let dispatcherConfig;
    let basicStoreDef = { getInitialState: emptyFunction, a: emptyFunction, b: emptyFunction, onActionA: emptyFunction, onActionB: emptyFunction };

    beforeEach(() => {
      api = createAPI();
      dispatcherConfig = { api, name: 'name' };
    });

    it('should should create a store', () => {
      let store = createStore(dispatcherConfig, {});
      expect(store.constructor.name).to.eql('Store');
    });

    it('should should subscribe to "onCapital" actions', () => {
      let store = createStore(dispatcherConfig, basicStoreDef);
      expect(store.subscriptions.length).to.eql(2);
      expect(store.subscriptions[0].listenable.actionName).to.eql('onActionA');
    });
    it('should should subscribe to [string] actions', () => {
      dispatcherConfig.actions = ['a', 'b', 'c'];
      let store = createStore(dispatcherConfig, basicStoreDef);
      expect(store.subscriptions.length).to.eql(2);
      expect(store.subscriptions[0].listenable.actionName).to.eql('a');
    });
    it('should should subscribe to filtered() actions', () => {
      dispatcherConfig.actions = (a) => {return a.includes('Action'); };
      let store = createStore(dispatcherConfig, basicStoreDef);
      expect(store.subscriptions.length).to.eql(2);
      expect(store.subscriptions[0].listenable.actionName).to.eql('onActionA');
    });

  });

});
<commit_msg>typos<commit_after>
import expect from 'expect.js';
import { createStore, createAPI } from '../src/index';
import { emptyFunction } from './testUtils';

describe('Cartiv Store', () => {
  it('Cartiv index should expose createStore', () => {
    expect(createStore).to.be.a('function');
  });

  describe('handle dispatcher config', () => {
    it('should throw if proper api not provided', () => {
      expect(createStore).withArgs({ api: '' }, {}).to.throwError();
      expect(createStore).withArgs({ api: {} }, {}).to.throwError();
      expect(createStore).withArgs({ api: { a: 1 } }, {}).to.throwError();
      expect(createStore).withArgs({ api: [] }, {}).to.throwError();
      expect(createStore).withArgs({ api: () => {} }, {}).to.throwError();
    });

    it('should throw if proper name not provided', () => {
      expect(createStore).withArgs({ name: {} }, {}).to.throwError();
      expect(createStore).withArgs({ name: { a: 1 } }, {}).to.throwError();
      expect(createStore).withArgs({ name: [] }, {}).to.throwError();
      expect(createStore).withArgs({ name: () => {} }, {}).to.throwError();
    });

    it('should throw if proper actions not provided', () => {
      expect(createStore).withArgs({ actions: {} }, {}).to.throwError();
      expect(createStore).withArgs({ actions: { a: 1 } }, {}).to.throwError();
      expect(createStore).withArgs({ actions: [] }, {}).to.throwError();
      expect(createStore).withArgs({ actions: ['a', {}] }, {}).to.throwError();
    });
  });

  describe('handle store definition', () => {
    let api;
    let dispatcherConfig;
    beforeEach(() => {
      api = createAPI();
      dispatcherConfig = { api, name: 'name' };
    });

    it('should throw if not provided or not plain object', () => {
      expect(createStore).withArgs(dispatcherConfig, '').to.throwError();
      expect(createStore).withArgs(dispatcherConfig, () => {}).to.throwError();
      expect(createStore).withArgs(dispatcherConfig, []).to.throwError();
      expect(createStore).withArgs(dispatcherConfig, undefined).to.throwError();
      expect(createStore).withArgs(dispatcherConfig, null).to.throwError();
    });

    it('should throw if getInitialState is not a function', () => {
      expect(createStore).withArgs(dispatcherConfig, { getInitialState: [] }).to.throwError();
      expect(createStore).withArgs(dispatcherConfig, { getInitialState: {} }).to.throwError();
      expect(createStore).withArgs(dispatcherConfig, { getInitialState: '123' }).to.throwError();
    });
  });

  describe('created Store', () => {
    let api;
    let dispatcherConfig;
    let basicStoreDef = { getInitialState: emptyFunction, a: emptyFunction, b: emptyFunction, onActionA: emptyFunction, onActionB: emptyFunction };

    beforeEach(() => {
      api = createAPI();
      dispatcherConfig = { api, name: 'name' };
    });

    it('should  create a store', () => {
      let store = createStore(dispatcherConfig, {});
      expect(store.constructor.name).to.eql('Store');
    });

    it('should subscribe to "onCapital" actions', () => {
      let store = createStore(dispatcherConfig, basicStoreDef);
      expect(store.subscriptions.length).to.eql(2);
      expect(store.subscriptions[0].listenable.actionName).to.eql('onActionA');
    });
    it('should subscribe to [string] actions', () => {
      dispatcherConfig.actions = ['a', 'b', 'c'];
      let store = createStore(dispatcherConfig, basicStoreDef);
      expect(store.subscriptions.length).to.eql(2);
      expect(store.subscriptions[0].listenable.actionName).to.eql('a');
    });
    it('should subscribe to filtered() actions', () => {
      dispatcherConfig.actions = (a) => {return a.includes('Action'); };
      let store = createStore(dispatcherConfig, basicStoreDef);
      expect(store.subscriptions.length).to.eql(2);
      expect(store.subscriptions[0].listenable.actionName).to.eql('onActionA');
    });

  });

});
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import { asyncConnect } from 'redux-connect';
import { autobind } from 'core-decorators';

import {
  Button,
  Card,
  CardActions,
  CardContent,
  CardList,
  CardTitle,
  renderMarkdown,
} from 'styled';
import kitten from './kitten.jpg';

@asyncConnect([{
  key: 'about',
  promise: ({ helpers: { client } }) => client.get('/about').then((res) => res.data.text),
}])
// eslint-disable-next-line react/prefer-stateless-function
export default class About extends React.Component {
  static propTypes = {
    about: PropTypes.any.isRequired,
  };

  state = {
    showKitten: false,
  }

  @autobind
  handleToggleKitten() {
    this.setState({ showKitten: !this.state.showKitten });
  }

  render() {
    const { showKitten } = this.state;
    return (
      <CardList>
        <Card>
          <CardTitle>About this project:</CardTitle>
          <CardContent>
            {renderMarkdown(this.props.about)}
          </CardContent>
        </Card>
        <Card>
          <CardContent>

Psst! Would you like to see a kitten?

            {showKitten && }
          </CardContent>
          <CardActions>
            <Button onClick={this.handleToggleKitten}>
              {showKitten ? 'No! Take it away!' : 'Yes! Please!'}
            </Button>
          </CardActions>
        </Card>
      </CardList>
    );
  }
}
<commit_msg>User @connect in About component<commit_after>import React, { PropTypes } from 'react';
import { asyncConnect } from 'redux-connect';
import { autobind } from 'core-decorators';

import {
  Button,
  Card,
  CardActions,
  CardContent,
  CardList,
  CardTitle,
  renderMarkdown,
} from 'styled';
import kitten from './kitten.jpg';

@asyncConnect([{
  promise: ({ helpers: { client } }) => client.get('/about').then((res) => res.data.text),
}])
@connect((state) => ({ about: getAbout(state) }))
// eslint-disable-next-line react/prefer-stateless-function
export default class About extends React.Component {
  static propTypes = {
    about: PropTypes.any.isRequired,
  };

  state = {
    showKitten: false,
  }

  @autobind
  handleToggleKitten() {
    this.setState({ showKitten: !this.state.showKitten });
  }

  render() {
    const { showKitten } = this.state;
    return (
      <CardList>
        <Card>
          <CardTitle>About this project:</CardTitle>
          <CardContent>
            {renderMarkdown(this.props.about)}
          </CardContent>
        </Card>
        <Card>
          <CardContent>

Psst! Would you like to see a kitten?

            {showKitten && }
          </CardContent>
          <CardActions>
            <Button onClick={this.handleToggleKitten}>
              {showKitten ? 'No! Take it away!' : 'Yes! Please!'}
            </Button>
          </CardActions>
        </Card>
      </CardList>
    );
  }
}
<|endoftext|>