main/WeatherWidget.js

import Cookies from '../vendor/jscookie';
import customEvent from '../utils/customEvent';
import populateElement from '../utils/populateElement';

/**
 * Weather Widget
 *
 * @example
* <div class="c-weather">
* 	<div class="c-weather__inner">
* 		<div class="c-loader c-weather__loader"></div>
*	 	<div class="c-weather__header">
*	 			<button class="c-weather__region toggle-switch"
*					data-toggle-outside-click="true" data-track-region="" data-title="CHANGE REGION">
*	 				<svg class="c-weather__icon c-icon" focusable="false">
*	 					<use xlink:href="" />
*	 				</svg>
*	 				<span class="c-weather__location" data-map="region_name"></span>
*	 				<span class="c-weather__province" data-map="region_state_abbr"></span>
*	 				<select class="c-weather__select toggle-on"></select>
*	 			</button>
*	 		</div>
*	 		<a class="c-weather__link c-weather__link--left"
*				data-map="weather_url" title="Weather" data-track-region="">
*	 			<div class="c-weather__imageContainer u-hide-tablet-landscape">
*	 				<img class="c-weather__image" data-map="icon" src="" alt="" />
*	 			</div>
*	 			<div class="c-weather__info">
*	 				<div class="c-weather__degree c-weather__degree--current" data-map="current"></div>
*	 				<div class="c-weather__prediction">
*	 					<span class="c-weather__degree" data-map="high"></span>
*	 					<span class="c-weather__degree" data-map="low"></span>
*	 				</div>
*	 			</div>
*	 		</a>
*	 		<a class="c-weather__link c-weather__link--right u-show-tablet-landscape"
*				data-map="weather_url" title="Weather" data-track-region="">
*	 			<div class="c-weather__imageContainer">
*	 				<div>
*	 					<img class="c-weather__image" data-map="icon" src=""  alt="" />
*	 					<div class="c-weather__text c-weather__conditions" data-map="conditions"></div>
*	 				</div>
*	 			</div>
*	 		</a>
*		</div>
* 		<a class="c-weather__link c-weather__link--bottom"
*			data-map="traffic_url" href="" data-track-region="">
* 			<span class="c-weather__label">Traffic</span>
* 			<span class="c-weather__text">Travel times & incidents</span>
* 			<div class="c-weather__traffic">
* 				<div class="c-weather__trafficTitle">
* 					<svg class="c-weather__alert c-icon" focusable="false">
* 						<use xlink:href="" />
* 					</svg>
* 					<span data-map="top_traffic_title"></span>
* 				</div>
* 				<span class="c-weather__trafficDesc" data-map="top_traffic_desc"></span>
* 			</div>
* 		</a>
* 	</div>
* </div>
 *
 * @module WeatherWidget
 * @prop {string} selector - DOM selector for a weather widget
 * @prop {string} regionButtonSelector - DOM selector for the region select button
 * @prop {string} dropdownSelector - DOM selector for the dropdown
 * @prop {string} regionLabelSelector - DOM selector for region label
 * @prop {string} loadingCss - CSS class of the loading state
 * @prop {string} hiddenCss - CSS class of the hidden state
 * @prop {string} cookieName - Cookie name for storing user selected region
 */
const WeatherWidget = {
	selector: '.c-weather',

	regionButtonSelector: '.c-weather__region',

	dropdownSelector: '.c-weather__select',

	regionLabelSelector: '[data-map="region_name"]',

	loadingCss: 'c-weather--loading',

	nightModeCSS: 'c-weather--night',

	trafficCSS: 'c-weather--traffic',

	hiddenCss: 'is-hidden',

	cookieName: 'gn-weatherRegion',

	/* global gnca_settings */

	/**
	 * Set up button click listener and region drop down listeners.
	 * Get weather data for selected region.
	 *
	 * @method init
	 */
	init() {
		const $targets = document.querySelectorAll( this.selector );

		[].forEach.call( $targets, ( $target, index ) => {
			const id = `c-weatherTraffic${index}`;
			$target.id = id; // eslint-disable-line no-param-reassign
			$target.classList.add( this.loadingCss );

			const $regionButton = $target.querySelector( this.regionButtonSelector );
			$regionButton.dataset.target = id;

			const $dropdown = $target.querySelector( this.dropdownSelector );
			$dropdown.addEventListener( 'change', evt => this.handleLocationChange( evt ) );
			$dropdown.dataset.target = id;
			$dropdown.setAttribute( 'size', 10 );

			const regionCode = Cookies.get( this.cookieName );

			this.getData( $target, gnca_settings.user_region, regionCode );
		});

		window.addEventListener( customEvent.REGION_CHANGE, () => this.handleRegionChange() );
	},

	/**
	 * Handler for location change.
	 * Get data for selected location.
	 *
	 * @method handleLocationChange
	 * @param {object} evt
	 */
	handleLocationChange( evt ) {
		const code = evt.target.selectedOptions[0].value;
		const $target = document.querySelector( `#${evt.currentTarget.dataset.target}` );
		const $label = $target.querySelector( this.regionLabelSelector );
		$label.textContent = evt.target.selectedOptions[0].textContent;

		evt.currentTarget.classList.add( this.hiddenCss );
		$target.querySelector( this.regionButtonSelector ).classList.remove( this.hiddenCss );
		$target.classList.add( this.loadingCss );

		this.trackRegionChange( $label.textContent, evt );
		this.getData( $target, gnca_settings.user_region, code );
	},

	/**
	 * Handler for region change by region picker.
	 * Clear weather region cookie.
	 *
	 * @method handleRegionChange
	 */
	handleRegionChange() {
		Cookies.remove( this.cookieName );
	},

	/**
	 * Track region change in Google and Adobe analytics
	 * @method trackRegionChange
	 */
	trackRegionChange( region, event ) {
		/* global gn_analytics */
		/* eslint-disable camelcase */
		if ( 'undefined' !== typeof ( gn_analytics ) && 'undefined' !== typeof ( gn_analytics.Analytics ) ) {
			const trackAction = `${region}`;
			gn_analytics.Analytics.track(['ga', 'adobe'], {
				eventType: 'Weather Region Change',
				action: trackAction,
				target: event.currentTarget,
				data: {
					weatherRegionChange: trackAction,
				},
			});
		}
		/* eslint-enable camelcase */
	},

	/**
	 * Get weather data for specified region and code
	 * Populate data into the target element and remember the selected region
	 *
	 * @method getData
	 * @param {element} $target
	 * @param {string} region
	 * @param {string} code
	 */
	getData( $target, region, code ) {
		const regionCode = 'string' === typeof ( code ) && 'undefined' !== code ? code : '';

		fetch( `/gnca-ajax-redesign/weather/{"default_region":"${region}","region_code":"${regionCode}"}` )
			.then( response => response.text() )
			.then( ( content ) => {
				const data = JSON.parse( content );
				this.populate( $target, data );

				$target.classList.remove( this.loadingCss );

				// Remember region code, if one exists
				if ( data.region_code ) {
					Cookies.set( this.cookieName, data.region_code, { expires: 90, path: '/' });
				}
			});
	},

	/**
	 * Populate data into target element
	 *
	 * @method populate
	 * @param {element} $target
	 * @param {object} data
	 */
	populate( $target, data ) {
		// Populate data fields in the widget
		populateElement( $target, data );

		// Update night mode if weather is at night
		if ( true === data.night_mode ) {
			$target.classList.add( this.nightModeCSS );
		} else {
			$target.classList.remove( this.nightModeCSS );
		}

		// Toggle traffic conditions mode if there are traffic conditions to show
		if ( true === data.has_top_traffic ) {
			$target.classList.add( this.trafficCSS );
		} else {
			$target.classList.remove( this.trafficCSS );
		}

		// Populate location picker for selected region
		const $dropdown = $target.querySelector( this.dropdownSelector );
		if ( 0 === $dropdown.querySelectorAll( 'option' ).length && data.region_picker ) {
			const regionList = data.region_picker;
			const regionCodes = Object.keys( regionList );

			[].forEach.call( regionCodes, ( code ) => {
				const $option = document.createElement( 'option' );
				$option.id = code;
				$option.setAttribute( 'value', code );
				$option.textContent = regionList[code];

				$dropdown.appendChild( $option );
			});
		}
	},
};

export default WeatherWidget;