<commit_before>// ***********************************************
// WINE LIFE
// DISCOVER WINDOW - DiscoverWindow.js
//
// MEN+1
// Programmer: Matthew Johnson
// ***********************************************

function DiscoverWindow(title) {

	var global = require('ui/common/globals');
	var dropdown = require('ui/common/elements/dropdown');
	var self = global.createWindow(title);
	self.barImage='images/iPhone_Nav_Bar_With_Bkgrd.png';
	var TU = require ('/TitanUp/TitanUp');

	// This view holds the wine list
	var view = Ti.UI.createView({
		top:'40%',
		left:0,
		width:'100%',
		height:'60%',
		layout: 'vertical'
	});

	var label_title = Ti.UI.createLabel({
		color: global.colors.dark,
		text:"Today's Featured Wines",
		font:{
            fontFamily:'Helvetica Neue',
            fontSize:18,
            fontWeight:'Bold'
           }
	});
//***********************************************************************************
//  This original list in the future will display advertised wines / picks of the day
//***********************************************************************************
	self.addEventListener('open', function(e){
		global.api.search_with_filter("Zinfandel", '124', function(search_results){
            table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
			});
		   view.add(label_title);
           view.add(table);
      });
	});

	self.add(view);

//************************************************************************
// Arrays with wines for picker menu's
//************************************************************************

 var allwines = ['Type', 'Amarone', 'Blanc', 'Carmenere', 'Cabernet', 'Chenin', 'Chianti',
 'Grand', 'Grenache', 'Grigio', 'Gris', 'Merlot', 'Murray', 'Muscat', 'Pinot Noir', 'Riesling',
  'Sangiovese', 'Shiraz', 'Syrah', 'Traminer', 'Verdicchio', 'Zinfandel'];

 var redwines =  ['Type','Amarone', 'Cabernet',
   'Grand', 'Grenache', 'Merlot', 'Pinot Noir',
  'Sangiovese', 'Shiraz', 'Syrah', 'Zinfandel'];

 var whitewines = ['Type','Blanc', 'Chenin',
  'Grigio', 'Gris', 'Murray', 'Muscat', 'Riesling',
  'Traminer', 'Verdicchio'];

// wines with filters not working
//  'Barolo', 'Carmenere', 'Chianti', 'Bordeaux',

// Drop down view
	var view_discover = Ti.UI.createView({
			width: Ti.UI.FILL,
			height: Ti.UI.SIZE,
			layout: 'vertical',
			left: 10,
			right: 10,
		});

	var wine_review = null;
	var table = null;

	// Dropdown menu components
	var search_bar = Ti.UI.createTextField({
		top:0,
		width:'90%',
		left:'5%',
		hintText:' Discover Wine...',
		borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED
	});

	var picker_color = TU.UI.createSimplePicker ({
		left: '5%',
		right: '5%',
		title: "Color",
		values: ['Color','Red', 'White']
	});

	var picker_allwines = TU.UI.createSimplePicker ({
		left: '5%',
		right: '5%',
		title: "Type",
		values: allwines
	});

	var picker_redwines = TU.UI.createSimplePicker ({
		left: '5%',
		right: '5%',
		title: "Type",
		values: redwines
	});

	var picker_whitewines = TU.UI.createSimplePicker ({
		left: '5%',
		right: '5%',
		title: "Type",
		values: whitewines
	});

	// These variables store picker selected values
	var winecolor = null; // this is for color id to refine search
	var wineColor = null;  // this is for actual wine color
	var winetype = null;

//*****************************************************************
//  Associative array used for server query filtering
//*****************************************************************

	var wines = new Object;
	wines['Amarone'] = '145';
	wines['Australian'] = '145';
	wines['Barolo'] = '170';
	wines['Blanc'] = '144';
	wines['Bordeaux'] = '-2147483648'; // Filter doesnt work
	wines['Cabernet'] = '139';
	wines['Carmenere'] = '10081';
	wines['Chenin'] = '163'; // Filter DNE
	wines['Chile'] = '10081';
	wines['Chianti'] = '139';
	wines['Grand'] = '10082';
	wines['Grenache'] = '10080';
	wines['Grigio'] = '194';
	wines['Gris'] = '194';
	wines['Merlot'] = '138';
	wines['Murray'] = '162';
	wines['Muscat'] = '173';
	wines['Pinot Noir'] = '143';
	wines['Riesling'] = '153';
	wines['Rose'] = '147';
	wines['Sangiovese'] = '163';
	wines['Shiraz'] = '146';
	wines['Syrah'] = '146';
	wines['Traminer'] = '148';
	wines['Verdicchio'] = '148';
	wines['Zinfandel'] = '141';

//******************************************************************************
// Event listener for wine color picker.  This function adds and removes views
// based off of what is selected in the picker.
//******************************************************************************
	picker_color.addEventListener ('TUchange', function (e) {
		if(e.value == 'Red'){
			winecolor = '124';
			wineColor = e.value;
			view_discover.remove(picker_allwines);
			view_discover.remove(picker_whitewines);
			view_discover.add(picker_redwines);

		picker_redwines.addEventListener ('TUchange', function (e) {
		winetype =  e.value;
		});

		}
		else if(e.value == "White"){
			winecolor = '125';
			wineColor = e.value;
			view_discover.remove(picker_allwines);
			view_discover.remove(picker_redwines);
			view_discover.add(picker_whitewines);

			picker_whitewines.addEventListener ('TUchange', function (e) {
			winetype =  e.value;
			});
		}
		else{
			winecolor = null;
			wineColor = null;
			view_discover.remove(picker_whitewines);
			view_discover.remove(picker_redwines);
			view_discover.add(picker_allwines);

			picker_allwines.addEventListener ('TUchange', function (e) {
			winetype =  e.value;
			});
		}

	});

	picker_allwines.addEventListener ('TUchange', function (e) {
	winetype =  e.value;
	});

	view_discover.add(search_bar);
	view_discover.add(picker_color);
	view_discover.add(picker_allwines);

//***********************************************************************************
// Dropdown menu area
// This function controls the dropdown menu and the logic for the pickers and
// search bar.
//***********************************************************************************
	dropdown(view_discover, self, "Find", "Browse", "down", function(){

		view.setTop('10%');
		view.setHeight('90%');
		view.remove(table);
		view.remove(label_title);
		self.remove(view);
		label_title.setText("Search Results");
		view.add(label_title);

		if(search_bar.value != null && search_bar.value != ""){

		if(winetype == 'Type'){winetype = null;}

			if(winecolor != null && winetype != null)
			{
				global.api.search_with_filter(search_bar.value, winecolor + '+' + wines[winetype], function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			  });
			}
			else if(winecolor == null && winetype != null)
			{
				global.api.search_with_filter(search_bar.value, wines[winetype], function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			  });
			}
			else if(winecolor != null && winetype == null)
			{
				global.api.search_with_filter(search_bar.value, winecolor, function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			 });
			}
			else
			{
				global.api.search(search_bar.value, function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			 });
			}

        self.add(view);

     }
     else{
     //	if nothing entered in textfield do these
     	if(winetype == 'Type'){winetype = null;}

			if(winecolor != null && winetype != null)
			{
				global.api.search_with_filter(winetype, winecolor + '+' + wines[winetype], function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			  });
			}
			else if(winecolor == null && winetype != null)
			{
				global.api.search_with_filter(winetype, wines[winetype], function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			  });
			}
			else if(winecolor != null && winetype == null)
			{
				global.api.search_with_filter(wineColor, winecolor, function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			 });
			}
			else if(winecolor == null && winetype == null)
			{
				//alert('Please Enter a Wine or Select a Filter to Search');
			}

     	self.add(view);
     }
	});

global.outputHook(self);
return self;
};

module.exports = DiscoverWindow;<commit_msg>discover filter Carmenere fixed<commit_after>// ***********************************************
// WINE LIFE
// DISCOVER WINDOW - DiscoverWindow.js
//
// MEN+1
// Programmer: Matthew Johnson
// ***********************************************

function DiscoverWindow(title) {

	var global = require('ui/common/globals');
	var dropdown = require('ui/common/elements/dropdown');
	var self = global.createWindow(title);
	self.barImage='images/iPhone_Nav_Bar_With_Bkgrd.png';
	var TU = require ('/TitanUp/TitanUp');

	// This view holds the wine list
	var view = Ti.UI.createView({
		top:'40%',
		left:0,
		width:'100%',
		height:'60%',
		layout: 'vertical'
	});

	var label_title = Ti.UI.createLabel({
		color: global.colors.dark,
		text:"Today's Featured Wines",
		font:{
            fontFamily:'Helvetica Neue',
            fontSize:18,
            fontWeight:'Bold'
           }
	});
//***********************************************************************************
//  This original list in the future will display advertised wines / picks of the day
//***********************************************************************************
	self.addEventListener('open', function(e){
		global.api.search_with_filter("Zinfandel", '124', function(search_results){
            table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
			});
		   view.add(label_title);
           view.add(table);
      });
	});

	self.add(view);

//************************************************************************
// Arrays with wines for picker menu's
//************************************************************************

 var allwines = ['Type', 'Amarone', 'Blanc', 'Carmenere', 'Cabernet', 'Chenin',
 'Grand', 'Grenache', 'Grigio', 'Gris', 'Merlot', 'Murray', 'Muscat', 'Pinot Noir', 'Riesling',
  'Sangiovese', 'Shiraz', 'Syrah', 'Traminer', 'Verdicchio', 'Zinfandel'];

 var redwines =  ['Type','Amarone', 'Cabernet', 'Carmenere',
   'Grand', 'Grenache', 'Merlot', 'Pinot Noir',
  'Sangiovese', 'Shiraz', 'Syrah', 'Zinfandel'];

 var whitewines = ['Type','Blanc', 'Chenin',
  'Grigio', 'Gris', 'Murray', 'Muscat', 'Riesling',
  'Traminer', 'Verdicchio'];

// wines with filters not working
//  'Barolo', 'Carmenere', 'Chianti', 'Bordeaux',

// Drop down view
	var view_discover = Ti.UI.createView({
			width: Ti.UI.FILL,
			height: Ti.UI.SIZE,
			layout: 'vertical',
			left: 10,
			right: 10,
		});

	var wine_review = null;
	var table = null;

	// Dropdown menu components
	var search_bar = Ti.UI.createTextField({
		top:0,
		width:'90%',
		left:'5%',
		hintText:' Discover Wine...',
		borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED
	});

	var picker_color = TU.UI.createSimplePicker ({
		left: '5%',
		right: '5%',
		title: "Color",
		values: ['Color','Red', 'White']
	});

	var picker_allwines = TU.UI.createSimplePicker ({
		left: '5%',
		right: '5%',
		title: "Type",
		values: allwines
	});

	var picker_redwines = TU.UI.createSimplePicker ({
		left: '5%',
		right: '5%',
		title: "Type",
		values: redwines
	});

	var picker_whitewines = TU.UI.createSimplePicker ({
		left: '5%',
		right: '5%',
		title: "Type",
		values: whitewines
	});

	// These variables store picker selected values
	var winecolor = null; // this is for color id to refine search
	var wineColor = null;  // this is for actual wine color
	var winetype = null;

//*****************************************************************
//  Associative array used for server query filtering
//*****************************************************************

	var wines = new Object;
	wines['Amarone'] = '145';
	wines['Australian'] = '145';
	wines['Barolo'] = '170';
	wines['Blanc'] = '144';
	wines['Bordeaux'] = '-2147483648'; // Filter doesnt work
	wines['Cabernet'] = '139';
	wines['Carmenere'] = '10081';
	wines['Chenin'] = '163'; // Filter DNE
	wines['Chile'] = '10081';
	wines['Chianti'] = '139';
	wines['Grand'] = '10082';
	wines['Grenache'] = '10080';
	wines['Grigio'] = '194';
	wines['Gris'] = '194';
	wines['Merlot'] = '138';
	wines['Murray'] = '162';
	wines['Muscat'] = '173';
	wines['Pinot Noir'] = '143';
	wines['Riesling'] = '153';
	wines['Rose'] = '147';
	wines['Sangiovese'] = '163';
	wines['Shiraz'] = '146';
	wines['Syrah'] = '146';
	wines['Traminer'] = '148';
	wines['Verdicchio'] = '148';
	wines['Zinfandel'] = '141';

//******************************************************************************
// Event listener for wine color picker.  This function adds and removes views
// based off of what is selected in the picker.
//******************************************************************************
	picker_color.addEventListener ('TUchange', function (e) {
		if(e.value == 'Red'){
			winecolor = '124';
			wineColor = e.value;
			view_discover.remove(picker_allwines);
			view_discover.remove(picker_whitewines);
			view_discover.add(picker_redwines);

		picker_redwines.addEventListener ('TUchange', function (e) {
		winetype =  e.value;
		});

		}
		else if(e.value == "White"){
			winecolor = '125';
			wineColor = e.value;
			view_discover.remove(picker_allwines);
			view_discover.remove(picker_redwines);
			view_discover.add(picker_whitewines);

			picker_whitewines.addEventListener ('TUchange', function (e) {
			winetype =  e.value;
			});
		}
		else{
			winecolor = null;
			wineColor = null;
			view_discover.remove(picker_whitewines);
			view_discover.remove(picker_redwines);
			view_discover.add(picker_allwines);

			picker_allwines.addEventListener ('TUchange', function (e) {
			winetype =  e.value;
			});
		}

	});

	picker_allwines.addEventListener ('TUchange', function (e) {
	winetype =  e.value;
	});

	view_discover.add(search_bar);
	view_discover.add(picker_color);
	view_discover.add(picker_allwines);

//***********************************************************************************
// Dropdown menu area
// This function controls the dropdown menu and the logic for the pickers and
// search bar.
//***********************************************************************************
	dropdown(view_discover, self, "Find", "Browse", "down", function(){

		view.setTop('10%');
		view.setHeight('90%');
		view.remove(table);
		view.remove(label_title);
		self.remove(view);
		label_title.setText("Search Results");
		view.add(label_title);

		if(search_bar.value != null && search_bar.value != ""){

		if(winetype == 'Type'){winetype = null;}

			if(winecolor != null && winetype != null)
			{
				global.api.search_with_filter(search_bar.value, winecolor + '+' + wines[winetype], function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			  });
			}
			else if(winecolor == null && winetype != null)
			{
				global.api.search_with_filter(search_bar.value, wines[winetype], function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			  });
			}
			else if(winecolor != null && winetype == null)
			{
				global.api.search_with_filter(search_bar.value, winecolor, function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			 });
			}
			else
			{
				global.api.search(search_bar.value, function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			 });
			}

        self.add(view);

     }
     else{
     //	if nothing entered in textfield do these
     	if(winetype == 'Type'){winetype = null;}

			if(winecolor != null && winetype != null)
			{
				global.api.search_with_filter(winetype, winecolor + '+' + wines[winetype], function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			  });
			}
			else if(winecolor == null && winetype != null)
			{
				global.api.search_with_filter(winetype, wines[winetype], function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			  });
			}
			else if(winecolor != null && winetype == null)
			{
				global.api.search_with_filter(wineColor, winecolor, function(search_results){
         		table = global.api.search_results(search_results, function(wine){
				wine_review = require('ui/handheld/WineReview');
				self.containingTab.open(wine_review(wine));
				});
				view.add(table);
			 });
			}
			else if(winecolor == null && winetype == null)
			{
				//alert('Please Enter a Wine or Select a Filter to Search');
			}

     	self.add(view);
     }
	});

global.outputHook(self);
return self;
};

module.exports = DiscoverWindow;<|endoftext|>


<commit_before>class FooClass {
    constructor() {
        this.a = 'hello';
        this.b = 'nodejs';
        this.c = 'world';
        this.d = '!';
    }

    __sleep() {
        this.sleepCalled = true;

        return [ 'a', 'c' ];
    }

    __wakeup() {
        this.wakeupCalled = true;
    }
}

module.exports = FooClass;
<commit_msg>[util] fix(test): fix serialization test (usage of undecleared field)<commit_after>class FooClass {
    constructor() {
        this.a = 'hello';
        this.b = 'nodejs';
        this.c = 'world';
        this.d = '!';
        this.sleepCalled = false;
        this.wakeupCalled = false;
    }

    __sleep() {
        this.sleepCalled = true;

        return [ 'a', 'c' ];
    }

    __wakeup() {
        this.wakeupCalled = true;
    }
}

module.exports = FooClass;
<|endoftext|>


<commit_before>function (user, context, callback) {
  // Imports
  const request = require('request');
  const YAML = require('js-yaml');
  const jose = require('node-jose');

  // Retrieve the access file information/configuration from well-known
  // See also https://github.com/mozilla-iam/cis/blob/profilev2/docs/.well-known/mozilla-iam.json
  function get_access_file_configuration(cb) {
    var access_file_conf = {};
    var options = { method: 'GET', url: configuration.iam_well_known };
    request(options, function (error, response, body) {
      if (error) throw new Error(error);
      if (response.statusCode !== 200) {
        console.log('Could not fetch access file URL: '+response.statusCode);
      } else {
        access_file_conf = JSON.parse(body).access_file;
        // contains mainly:
        // access_file_conf.endpoint  (URL)
        // access_file_conf.jwks.keys[]{} (pub keys)
        // access_file_conf.aai_mappings
      }
      return cb(access_file_conf);
    });
  }

  // Retrieve and verify access rule file itself
  function get_verified_access_rules(cb, access_file_conf) {
    // Bypass if we have a cached version present already
    // Cache is very short lived in webtask, it just means we hit a "hot" task which nodejs process hasn't yet been
    // terminated. Generally this means we hit the same task within 60s.
    if (global.access_rules) {
      return cb(global.access_rules, access_file_conf);
    }

    var options = { method: 'GET', url: access_file_conf.endpoint };
    var decoded;
    request(options, function (error, response, body) {
      if (error) throw new Error(error);
      // Convert key into jose-formatted-key
      // XXX remove this part of the code when well-known and signature exists
      if (access_file_conf.jwks === null) {
        console.log('WARNING: Bypassing access file signature verification');
        decoded = body;
      } else {
        // XXX verify key format when the well-known endpoint exists
        var pubkey = jose.JWK.asKey(access_file_conf.jwks.keys.x5c[0], 'pem').then((jwk) => jwk);
        var verifier = jose.JWS.createVerify(pubkey);
        var ret = verifier.verify(body).then((response) => response.payload).catch((err) => err);
        decoded = ret.then((data) => data).catch((err) => {
          throw new Error('Signature verification of access file failed (fatal): '+err);
        });
      }

      global.access_rules = YAML.load(decoded).apps;
      return cb(global.access_rules, access_file_conf);
    });
  }

  // Check if array A has any occurrence from array B
  function array_in_array(A, B) {
    var found = A.some(
      function(item) {
        if (!B)
          return false;
        return B.indexOf(item) >= 0;
    });
    return found;
  }

  // Update expiration and grant access
  function access_granted(a, b, c) {
    updateAccessExpiration();
    return callback(a, b, c);
  }

  // Deny access
  function access_denied(a, b, c) {
    return callback(a, b, c);
  }

  // updateAccessExpiration()
  // Always returns - will attempt to update user.app_metadata.authoritativeGroups[].lastUsed timestamp
  // for the RP/client_id we're currently trying to login to
  // XXX Use Profilev2 when available
  function updateAccessExpiration() {
      user.app_metadata = user.app_metadata || {};
      if (user.app_metadata.authoritativeGroups === undefined) {
          console.log('ExpirationOfAccess: not enabled for this user');
          return;
      }

      var updated = false;
      for (var index = 0;index < user.app_metadata.authoritativeGroups.length;++index) {
        if (user.app_metadata.authoritativeGroups[index].uuid === context.clientID) {
          user.app_metadata.authoritativeGroups[index].lastUsed = new Date();
          updated = true;
          break; // we're done
        }
      }
      if (updated === true) {
        auth0.users.updateAppMetadata(user.user_id, user.app_metadata)
          .catch(function(err) {
          console.log('ExpirationOfAccess: Error updating app_metadata (AuthoritativeGroups) for user '+user.user_id+': '+err);
        });
      }
      console.log('ExpirationOfAccess: Updated lastUsed for '+user.user_id);
      return;
  }

  // Process the access cache decision
  function access_decision(access_rules, access_file_conf) {
    // Use whatever is available from the group struct. Sometimes there's a race condition where user.app_metadata.*
    // isnt reintegrated to user.* for example
    var groups = user.app_metadata.groups || user.groups || [];
    // Defaut app requested aai level to MEDIUM for all apps which do not have this set in access file
    var required_aai_level = "MEDIUM";

    for (var i=0; i<access_rules.length; i++) {
      var app = access_rules[i].application;

      //Handy for quick testing in dev (overrides access rules)
      //var app = {'client_id': 'pCGEHXW0VQNrQKURDcGi0tghh7NwWGhW', // This is testrp social-ldap-pwless
      //           'authorized_users': ['gdestuynder@mozilla.com'],
      //           'authorized_groups': ['okta_mfa'],
      //           'expire_access_when_unused_after': 86400,
      //           'aai': 'LOW'
      //          };

      if (app.client_id && (app.client_id.indexOf(context.clientID) >= 0)) {
        // Set app AAI level if present
        required_aai_level = app.aai || required_aai_level;

        // EXPIRATION OF ACCESS
        // Note that the expiration check MUST always run first
        // Check if the user access to the RP has expired due to ExpirationOfAccess
        if ((app.expire_access_when_unused_after !== undefined) && (app.expire_access_when_unused_after > 0)) {
          user.app_metadata = user.app_metadata || {};
          // If the user has no authoritativeGroups for this clientID, let the user in
          if (user.app_metadata.authoritativeGroups !== undefined) {
            for (var index=0;index < user.app_metadata.authoritativeGroups.length; ++index) {
              if (user.app_metadata.authoritativeGroups[index].uuid === context.clientID) {
                // Find the delta for this user and see if access should have expired
                var lastUsed_ts = new Date(user.app_metadata.authoritativeGroups[index].lastUsed).getTime();
                var delta = new Date().getTime() - lastUsed_ts;
                // Access expired?
                if (delta > app.expire_access_when_unused_after) {
                    // Do not allow the user in, no matter what other access has been set
                    console.log("Access denied to "+context.clientID+" for user "+user.email+" ("+user.user_id+") - access has expired");
                    return access_denied(null, user, global.postError('accesshasexpired', context));
                }
                break;
              }
            }
          }
        }

        // AUTHORIZED_{GROUPS,USERS}
        // XXX this authorized_users SHOULD BE REMOVED as it's unsafe (too easy to make mistakes). USE GROUPS.
        // XXX This needs to be fixed in the dashboard first
        // Empty users or groups (length == 0) means no access in the dashboard apps.yml world
        if (app.authorized_users.length === app.authorized_groups.length === 0) {
          console.log("Access denied to "+context.clientID+" for user "+user.email+" ("+user.user_id+") - this app denies ALL users and ALL groups");
          return access_denied(null, user, global.postError('notingroup', context));
        }

        // Check if the user is authorized to access
        if ((app.authorized_users.length > 0 ) && (app.authorized_users.indexOf(user.email) >= 0)) {
          return access_granted(null, user, context);
        // Same dance as above, but for groups
        } else if ((app.authorized_groups.length > 0) && array_in_array(app.authorized_groups, groups)) {
          return access_granted(null, user, context);
        }

        console.log("Access denied to "+context.clientID+" for user "+user.email+" ("+user.user_id+") - not in authorized group or not an authorized user");
        return access_denied(null, user, global.postError('notingroup', context));
      } // correct client id / we matched the current RP
    } // for loop / next rule in apps.yml

    // AAI (AUTHENTICATOR ASSURANCE INDICATOR) REQUIREMENTS
    //
    // Note that user.aai is set in another rule (rules/aai.js)
    //
    // Mapping logic and verification
    // Ex: our mapping says 2FA for MEDIUM AAI and app AAI is MEDIUM as well, and the user has 2FA AAI, looks like:
    // access_file_conf.aai_mapping['MEDIUM'] = ['2FA'];
    // app.aai = 'MEDIUM;
    // user.aai = ['2FA'];
    // Thus user should be allowed for this app (it requires MEDIUM, and MEDIUM requires 2FA, and user has 2FA
    // indeed)

    var aai_pass = false;
    if ((access_file_conf.aai_mapping !== undefined) && (access_file_conf.aai_mapping[required_aai_level].length === 0)) {
      // No required indicator in aai_mapping for this app's requested AAI
      aai_pass = true;
    } else {
      for (var y=0; y<user.aai.length; y++) {
        var this_aai = user.aai[y];
        if (access_file_conf.aai_mapping[required_aai_level].indexOf(this_aai) >= 0) {
          aai_pass = true;
          break;
        }
      }
    }

    if (!aai_pass) {
      console.log("Access denied to "+context.clientID+" for user "+user.email+" ("+user.user_id+") - due to " +
        "Identity Assurance Verification being too low for this RP: Required AAI: "+required_aai_level+
        "("+aai_pass+")"); return access_denied(null, user, global.postError('aai_failed', context));
    } else {
      // Inform RPs of which AAI level let the user in
      var namespace = 'https://sso.mozilla.com/claim/';
      context.idToken[namespace+"AAI_LEVEL"] = required_aai_level;
    }

    // We matched no rule, access is granted
    return access_granted(null, user, context);
  }

  // "Main" starts here
  // This is a fake access file conf similar to the well-known endpoint,
  // until the well-known endpoint is actually available - it is also not signed and disables signing verification
  const fake_access_file_conf = { endpoint: 'https://cdn.sso.mozilla.com/apps.yml', jwks: null,
    aai_mapping: {
      "LOW": [],
      "MEDIUM": ["2FA", "HIGH_ASSURANCE_IDP"],
      "HIGH": [],
      "MAXIMUM": []
    }
  };
  // Get access file configuration, then get the access rules (apps.yml), then give all this to the access_decision()
  // function to decide if the user should be allowed or not. Any failure along the way will forbid the user to get in.
  return get_access_file_configuration(function(access_file_conf) {
    return get_verified_access_rules(access_decision, fake_access_file_conf);
  });
}
<commit_msg>Ensure the authorized user/group logic cannot bypass non-access file checks (such as AAI defaults)<commit_after>function (user, context, callback) {
  // Imports
  const request = require('request');
  const YAML = require('js-yaml');
  const jose = require('node-jose');

  // Retrieve the access file information/configuration from well-known
  // See also https://github.com/mozilla-iam/cis/blob/profilev2/docs/.well-known/mozilla-iam.json
  function get_access_file_configuration(cb) {
    var access_file_conf = {};
    var options = { method: 'GET', url: configuration.iam_well_known };
    request(options, function (error, response, body) {
      if (error) throw new Error(error);
      if (response.statusCode !== 200) {
        console.log('Could not fetch access file URL: '+response.statusCode);
      } else {
        access_file_conf = JSON.parse(body).access_file;
        // contains mainly:
        // access_file_conf.endpoint  (URL)
        // access_file_conf.jwks.keys[]{} (pub keys)
        // access_file_conf.aai_mappings
      }
      return cb(access_file_conf);
    });
  }

  // Retrieve and verify access rule file itself
  function get_verified_access_rules(cb, access_file_conf) {
    // Bypass if we have a cached version present already
    // Cache is very short lived in webtask, it just means we hit a "hot" task which nodejs process hasn't yet been
    // terminated. Generally this means we hit the same task within 60s.
    if (global.access_rules) {
      return cb(global.access_rules, access_file_conf);
    }

    var options = { method: 'GET', url: access_file_conf.endpoint };
    var decoded;
    request(options, function (error, response, body) {
      if (error) throw new Error(error);
      // Convert key into jose-formatted-key
      // XXX remove this part of the code when well-known and signature exists
      if (access_file_conf.jwks === null) {
        console.log('WARNING: Bypassing access file signature verification');
        decoded = body;
      } else {
        // XXX verify key format when the well-known endpoint exists
        var pubkey = jose.JWK.asKey(access_file_conf.jwks.keys.x5c[0], 'pem').then((jwk) => jwk);
        var verifier = jose.JWS.createVerify(pubkey);
        var ret = verifier.verify(body).then((response) => response.payload).catch((err) => err);
        decoded = ret.then((data) => data).catch((err) => {
          throw new Error('Signature verification of access file failed (fatal): '+err);
        });
      }

      global.access_rules = YAML.load(decoded).apps;
      return cb(global.access_rules, access_file_conf);
    });
  }

  // Check if array A has any occurrence from array B
  function array_in_array(A, B) {
    var found = A.some(
      function(item) {
        if (!B)
          return false;
        return B.indexOf(item) >= 0;
    });
    return found;
  }

  // Update expiration and grant access
  function access_granted(a, b, c) {
    updateAccessExpiration();
    return callback(a, b, c);
  }

  // Deny access
  function access_denied(a, b, c) {
    return callback(a, b, c);
  }

  // updateAccessExpiration()
  // Always returns - will attempt to update user.app_metadata.authoritativeGroups[].lastUsed timestamp
  // for the RP/client_id we're currently trying to login to
  // XXX Use Profilev2 when available
  function updateAccessExpiration() {
      user.app_metadata = user.app_metadata || {};
      if (user.app_metadata.authoritativeGroups === undefined) {
          console.log('ExpirationOfAccess: not enabled for this user');
          return;
      }

      var updated = false;
      for (var index = 0;index < user.app_metadata.authoritativeGroups.length;++index) {
        if (user.app_metadata.authoritativeGroups[index].uuid === context.clientID) {
          user.app_metadata.authoritativeGroups[index].lastUsed = new Date();
          updated = true;
          break; // we're done
        }
      }
      if (updated === true) {
        auth0.users.updateAppMetadata(user.user_id, user.app_metadata)
          .catch(function(err) {
          console.log('ExpirationOfAccess: Error updating app_metadata (AuthoritativeGroups) for user '+user.user_id+': '+err);
        });
      }
      console.log('ExpirationOfAccess: Updated lastUsed for '+user.user_id);
      return;
  }

  // Process the access cache decision
  function access_decision(access_rules, access_file_conf) {
    // Use whatever is available from the group struct. Sometimes there's a race condition where user.app_metadata.*
    // isnt reintegrated to user.* for example
    var groups = user.app_metadata.groups || user.groups || [];
    // This is used for authorized user/groups
    var authorized = false;
    // Defaut app requested aai level to MEDIUM for all apps which do not have this set in access file
    var required_aai_level = "MEDIUM";

    for (var i=0; i<access_rules.length; i++) {
      var app = access_rules[i].application;

      //Handy for quick testing in dev (overrides access rules)
      //var app = {'client_id': 'pCGEHXW0VQNrQKURDcGi0tghh7NwWGhW', // This is testrp social-ldap-pwless
      //           'authorized_users': ['gdestuynder@mozilla.com'],
      //           'authorized_groups': ['okta_mfa'],
      //           'expire_access_when_unused_after': 86400,
      //           'aai': 'LOW'
      //          };

      if (app.client_id && (app.client_id.indexOf(context.clientID) >= 0)) {
        // Set app AAI level if present
        required_aai_level = app.aai || required_aai_level;

        // EXPIRATION OF ACCESS
        // Note that the expiration check MUST always run first
        // Check if the user access to the RP has expired due to ExpirationOfAccess
        if ((app.expire_access_when_unused_after !== undefined) && (app.expire_access_when_unused_after > 0)) {
          user.app_metadata = user.app_metadata || {};
          // If the user has no authoritativeGroups for this clientID, let the user in
          if (user.app_metadata.authoritativeGroups !== undefined) {
            for (var index=0;index < user.app_metadata.authoritativeGroups.length; ++index) {
              if (user.app_metadata.authoritativeGroups[index].uuid === context.clientID) {
                // Find the delta for this user and see if access should have expired
                var lastUsed_ts = new Date(user.app_metadata.authoritativeGroups[index].lastUsed).getTime();
                var delta = new Date().getTime() - lastUsed_ts;
                // Access expired?
                if (delta > app.expire_access_when_unused_after) {
                    // Do not allow the user in, no matter what other access has been set
                    console.log("Access denied to "+context.clientID+" for user "+user.email+" ("+user.user_id+") - access has expired");
                    return access_denied(null, user, global.postError('accesshasexpired', context));
                }
                break;
              }
            }
          }
        }

        // AUTHORIZED_{GROUPS,USERS}
        // XXX this authorized_users SHOULD BE REMOVED as it's unsafe (too easy to make mistakes). USE GROUPS.
        // XXX This needs to be fixed in the dashboard first
        // Empty users or groups (length == 0) means no access in the dashboard apps.yml world
        if (app.authorized_users.length === app.authorized_groups.length === 0) {
          console.log("Access denied to "+context.clientID+" for user "+user.email+" ("+user.user_id+") - this app denies ALL users and ALL groups");
          return access_denied(null, user, global.postError('notingroup', context));
        }

        // Check if the user is authorized to access
        if ((app.authorized_users.length > 0 ) && (app.authorized_users.indexOf(user.email) >= 0)) {
          authorized = true;
        // Same dance as above, but for groups
        } else if ((app.authorized_groups.length > 0) && array_in_array(app.authorized_groups, groups)) {
          authorized = true;
        } else {
          authorized = false;
        }

        if (!authorized) {
          console.log("Access denied to "+context.clientID+" for user "+user.email+" ("+user.user_id+") - not in authorized group or not an authorized user");
          return access_denied(null, user, global.postError('notingroup', context));
        }
      } // correct client id / we matched the current RP
    } // for loop / next rule in apps.yml

    // AAI (AUTHENTICATOR ASSURANCE INDICATOR) REQUIREMENTS
    //
    // Note that user.aai is set in another rule (rules/aai.js)
    //
    // Mapping logic and verification
    // Ex: our mapping says 2FA for MEDIUM AAI and app AAI is MEDIUM as well, and the user has 2FA AAI, looks like:
    // access_file_conf.aai_mapping['MEDIUM'] = ['2FA'];
    // app.aai = 'MEDIUM;
    // user.aai = ['2FA'];
    // Thus user should be allowed for this app (it requires MEDIUM, and MEDIUM requires 2FA, and user has 2FA
    // indeed)

    var aai_pass = false;
    if ((access_file_conf.aai_mapping !== undefined) && (access_file_conf.aai_mapping[required_aai_level].length === 0)) {
      // No required indicator in aai_mapping for this app's requested AAI
      aai_pass = true;
    } else {
      for (var y=0; y<user.aai.length; y++) {
        var this_aai = user.aai[y];
        if (access_file_conf.aai_mapping[required_aai_level].indexOf(this_aai) >= 0) {
          aai_pass = true;
          break;
        }
      }
    }

    if (!aai_pass) {
      console.log("Access denied to "+context.clientID+" for user "+user.email+" ("+user.user_id+") - due to " +
        "Identity Assurance Verification being too low for this RP: Required AAI: "+required_aai_level+
        "("+aai_pass+")"); return access_denied(null, user, global.postError('aai_failed', context));
    } else {
      // Inform RPs of which AAI level let the user in
      var namespace = 'https://sso.mozilla.com/claim/';
      context.idToken[namespace+"AAI_LEVEL"] = required_aai_level;
    }

    // We matched no rule, access is granted
    return access_granted(null, user, context);
  }

  // "Main" starts here
  // This is a fake access file conf similar to the well-known endpoint,
  // until the well-known endpoint is actually available - it is also not signed and disables signing verification
  const fake_access_file_conf = { endpoint: 'https://cdn.sso.mozilla.com/apps.yml', jwks: null,
    aai_mapping: {
      "LOW": [],
      "MEDIUM": ["2FA", "HIGH_ASSURANCE_IDP"],
      "HIGH": [],
      "MAXIMUM": []
    }
  };
  // Get access file configuration, then get the access rules (apps.yml), then give all this to the access_decision()
  // function to decide if the user should be allowed or not. Any failure along the way will forbid the user to get in.
  return get_access_file_configuration(function(access_file_conf) {
    return get_verified_access_rules(access_decision, fake_access_file_conf);
  });
}
<|endoftext|>


<commit_before>function (user, context, callback) {
  // /!\ DO NOT EDIT THIS FILE /!\
  // Please use http://github.com/mozilla-iam/auth0-rules instead

  // LDAP group okta_mfa requires MFA authentication everywhere.
  if (user.groups && user.groups.indexOf("okta_mfa")) {
    context.multifactor = {
      provider: 'duo',
      ikey: configuration.duo_ikey_mozilla,
      skey: configuration.duo_skey_mozilla,
      host: configuration.duo_apihost_mozilla,

      // optional:
      // Force DuoSecurity everytime this rule runs. Defaults to false.
      // If accepted by users the cookie lasts for 30 days - i.e. 30 days MFA session (this cannot be changed)
      ignoreCookie: false,
      username: user.email,
    };
  }
  callback(null, user, context);
}
<commit_msg>In a condition, -1 does not equal "false" (only in a test)<commit_after>function (user, context, callback) {
  // /!\ DO NOT EDIT THIS FILE /!\
  // Please use http://github.com/mozilla-iam/auth0-rules instead

  // LDAP group okta_mfa requires MFA authentication everywhere.
  if (user.groups && user.groups.indexOf("okta_mfa") !== -1) {
    context.multifactor = {
      provider: 'duo',
      ikey: configuration.duo_ikey_mozilla,
      skey: configuration.duo_skey_mozilla,
      host: configuration.duo_apihost_mozilla,

      // optional:
      // Force DuoSecurity everytime this rule runs. Defaults to false.
      // If accepted by users the cookie lasts for 30 days - i.e. 30 days MFA session (this cannot be changed)
      ignoreCookie: false,
      username: user.email,
    };
  }
  callback(null, user, context);
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import momentJalaali from 'moment-jalaali';
import TetherComponent from 'react-tether';
import classnames from 'classnames';
import Calendar from './Calendar';
import MyTimePicker from './CustomTimePicker';

const outsideClickIgnoreClass = 'ignore--click--outside';

export default class DatePicker extends Component {
  static propTypes = {
    value: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
    defaultValue: PropTypes.object,
    onChange: PropTypes.func,
    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    children: PropTypes.node,
    min: PropTypes.object,
    max: PropTypes.object,
    defaultYear: PropTypes.object,
    defaultMonth: PropTypes.object,
    inputFormat: PropTypes.string,
    inputJalaaliFormat: PropTypes.string,
    removable: PropTypes.bool,
    styles: PropTypes.object,
    calendarStyles: PropTypes.object,
    calendarContainerProps: PropTypes.object,
    isGregorian: PropTypes.bool, // jalaali or gregorian
    timePicker: PropTypes.bool,
    calendarClass: PropTypes.string,
    datePickerClass: PropTypes.string,
    tetherAttachment: PropTypes.string,
    inputReadOnly: PropTypes.bool,
    ranges: PropTypes.array,
    showToggleButton: PropTypes.bool,
    toggleButtonText: PropTypes.any,
    showTodayButton: PropTypes.bool,
    placeholder: PropTypes.string
  };

  static defaultProps = {
    styles: undefined,
    calendarContainerProps: {},
    isGregorian: true,
    timePicker: true,
    showTodayButton: true,
    placeholder: ''
  };

  constructor(props) {
    super(props);
    // create a ref to store the textInput DOM element
    this.textInput = React.createRef();

    this.state = {
      isOpen: false,
      momentValue: this.props.defaultValue || null,
      inputValue: this.getValue(
        this.props.defaultValue,
        this.props.isGregorian,
        this.props.timePicker
      ),
      inputJalaaliFormat:
        this.props.inputJalaaliFormat || this.getInputFormat(false, this.props.timePicker),
      inputFormat: this.props.inputFormat || this.getInputFormat(true, this.props.timePicker),
      isGregorian: this.props.isGregorian,
      timePicker: this.props.timePicker,
      timePickerComponent: this.props.timePicker ? MyTimePicker : undefined
    };
  }

  getInputFormat(isGregorian, timePicker) {
    if (timePicker) return isGregorian ? 'YYYY/M/D hh:mm A' : 'jYYYY/jM/jD hh:mm A';
    return isGregorian ? 'YYYY/M/D' : 'jYYYY/jM/jD';
  }

  getValue(inputValue, isGregorian, timePicker) {
    if (!inputValue) return '';
    let { inputFormat } = this.state;
    let { inputJalaaliFormat } = this.state;
    if (!inputFormat) inputFormat = this.getInputFormat(isGregorian, timePicker);
    if (!inputJalaaliFormat) inputJalaaliFormat = this.getInputFormat(isGregorian, timePicker);

    return isGregorian
      ? inputValue.locale('es').format(inputFormat)
      : inputValue.locale('fa').format(inputJalaaliFormat);
  }

  setOpen = isOpen => {
    this.setState({ isOpen });

    if (this.props.onOpen) {
      this.props.onOpen(isOpen);
    }
  };

  UNSAFE_componentWillMount() {
    if (this.props.value) {
      this.setMomentValue(this.props.value);
    }
  }

  UNSAFE_componentWillReceiveProps(nextProps) {
    if ('value' in nextProps && nextProps.value !== this.props.value) {
      this.setMomentValue(nextProps.value);
    }

    if ('isGregorian' in nextProps && nextProps.isGregorian !== this.props.isGregorian) {
      const { inputFormat: nextPropsInputFormat } = nextProps;
      const { inputJalaaliFormat: nextPropsInputJalaaliFormat } = nextProps;

      this.setState({
        isGregorian: nextProps.isGregorian,
        inputValue: this.getValue(nextProps.value, nextProps.isGregorian, nextProps.timePicker),
        inputFormat: nextPropsInputFormat || this.state.inputFormat,
        inputJalaaliFormat: nextPropsInputJalaaliFormat || this.state.inputJalaaliFormat
      });
    }

    if ('timePicker' in nextProps && nextProps.timePicker !== this.props.timePicker) {
      this.setState({
        timePicker: nextProps.timePicker,
        timePickerComponent: this.props.timePicker ? MyTimePicker : undefined
      });
    }
  }

  toggleMode = () => {
    const isGregorian = !this.state.isGregorian;
    const { inputFormat: nextPropsInputFormat } = this.props;
    const { inputJalaaliFormat: nextPropsInputJalaaliFormat } = this.props;
    this.setState({
      isGregorian: isGregorian,
      inputValue: this.getValue(this.props.value, isGregorian, this.props.timePicker)
    });
  };

  setMomentValue(momentValue) {
    const { inputFormat, isGregorian, timePicker } = this.state;

    if (this.props.onChange) {
      this.props.onChange(momentValue);
    }

    const inputValue = this.getValue(momentValue, isGregorian, timePicker);

    this.setState({ momentValue, inputValue });
  }

  handleFocus = () => {
    this.setOpen(true);
  };

  handleClickOutsideCalendar() {
    this.setOpen(false);
  }

  toEnglishDigits(str) {
    if (!str) return str;
    const regex1 = /[\u0660-\u0669]/g;
    const regex2 = /[\u06f0-\u06f9]/g;
    return str
      .replace(regex1, function(c) {
        return c.charCodeAt(0) - 0x0660;
      })
      .replace(regex2, function(c) {
        return c.charCodeAt(0) - 0x06f0;
      });
  }

  toPersianDigits(str) {
    if (!str) return str;
    const regex = /[0-9]/g;
    const id = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
    return str.replace(regex, function(w) {
      return id[+w];
    });
  }

  handleSelectDay(selectedDay) {
    const { momentValue: oldValue } = this.state;
    let momentValue = selectedDay.clone();

    if (oldValue) {
      momentValue = momentValue.set({
        hour: oldValue.hours(),
        minute: oldValue.minutes(),
        second: oldValue.seconds()
      });
    }
    this.setOpen(false);
    this.setMomentValue(momentValue);
  }

  handleInputChange(event) {
    const { inputFormat, inputJalaaliFormat, isGregorian } = this.state;
    const inputValue = this.toEnglishDigits(event.target.value);
    const currentInputFormat = isGregorian ? inputFormat : inputJalaaliFormat;

    const momentValue = momentJalaali(inputValue, currentInputFormat);

    if (momentValue.isValid()) {
      this.setState({ momentValue });
      if (this.props.onChange) {
        this.props.onChange(momentValue);
      }
    }
    else if(inputValue === ''){
      if (this.props.onChange) {
        this.props.onChange('');
      }
    }

    this.setState({ inputValue });
  }

  handleInputClick() {
    if (!this.props.disabled) {
      this.setOpen(true);
    }
  }

  renderInput = ref => {
    const { isOpen, inputValue, isGregorian } = this.state;

    const className = classnames(this.props.className, {
      [outsideClickIgnoreClass]: isOpen
    });

    return (

        <input
          placeholder={this.props.placeholder}
          className={`datepicker-input ${className}`}
          type="text"
          ref={inst => {
            this.input = inst;
          }}
          onFocus={this.handleFocus.bind(this)}
          onChange={this.handleInputChange.bind(this)}
          onClick={this.handleInputClick.bind(this)}
          value={isGregorian ? inputValue : this.toPersianDigits(inputValue)}
          readOnly={this.props.inputReadOnly === true}
          disabled={this.props.disabled}
        />

    );
  };

  renderCalendar = ref => {
    const { momentValue, isGregorian, timePickerComponent: TimePicker } = this.state;
    const { onChange, min, max, defaultYear, defaultMonth, styles, calendarContainerProps, ranges } = this.props;

    return (

        <Calendar
          toggleMode={this.toggleMode}
          ranges={ranges}
          min={min}
          max={max}
          selectedDay={momentValue}
          defaultYear={defaultYear}
          defaultMonth={defaultMonth}
          onSelect={this.handleSelectDay.bind(this)}
          onClickOutside={this.handleClickOutsideCalendar.bind(this)}
          outsideClickIgnoreClass={outsideClickIgnoreClass}
          styles={styles}
          containerProps={calendarContainerProps}
          isGregorian={isGregorian}
          calendarClass={this.props.calendarClass ? this.props.calendarClass : ''}
          showToggleButton={this.props.showToggleButton}
          toggleButtonText={this.props.toggleButtonText}
          showTodayButton={this.props.showTodayButton}
          timePicker={
            TimePicker ? (
              <TimePicker
                outsideClickIgnoreClass={outsideClickIgnoreClass}
                isGregorian={isGregorian}
                min={min}
                max={max}
                momentValue={momentValue}
                setMomentValue={this.setMomentValue.bind(this)}
              />
            ) : null
          }
        />

    );
  };

  removeDate() {
    const { onChange } = this.props;
    if (onChange) {
      onChange('');
    }
    this.setState({
      input: '',
      inputValue: ''
    });
  }

  render() {
    const { isOpen } = this.state;

    return (
      <TetherComponent
        ref={tether => (this.tether = tether)}
        attachment={this.props.tetherAttachment ? this.props.tetherAttachment : 'top center'}
        constraints={[
          {
            to: 'window',
            attachment: 'together'
          }
        ]}
        offset="-10px -10px"
        onResize={() => this.tether && this.tether.position()}
        /* renderTarget: This is what the item will be tethered to, make sure to attach the ref */
        renderTarget={ref => this.renderInput(ref)}
        /* renderElement: If present, this item will be tethered to the the component returned by renderTarget */
        renderElement={ref => isOpen && this.renderCalendar(ref)}
      />
    );
  }
}
<commit_msg>Update DatePicker.js<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import momentJalaali from 'moment-jalaali';
import TetherComponent from 'react-tether';
import classnames from 'classnames';
import Calendar from './Calendar';
import MyTimePicker from './CustomTimePicker';

const outsideClickIgnoreClass = 'ignore--click--outside';

export default class DatePicker extends Component {
  static propTypes = {
    value: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
    defaultValue: PropTypes.object,
    onChange: PropTypes.func,
    onInputChange: PropTypes.func,
    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    children: PropTypes.node,
    min: PropTypes.object,
    max: PropTypes.object,
    defaultYear: PropTypes.object,
    defaultMonth: PropTypes.object,
    inputFormat: PropTypes.string,
    inputJalaaliFormat: PropTypes.string,
    removable: PropTypes.bool,
    styles: PropTypes.object,
    calendarStyles: PropTypes.object,
    calendarContainerProps: PropTypes.object,
    isGregorian: PropTypes.bool, // jalaali or gregorian
    timePicker: PropTypes.bool,
    calendarClass: PropTypes.string,
    datePickerClass: PropTypes.string,
    tetherAttachment: PropTypes.string,
    inputReadOnly: PropTypes.bool,
    ranges: PropTypes.array,
    showToggleButton: PropTypes.bool,
    toggleButtonText: PropTypes.any,
    showTodayButton: PropTypes.bool,
    placeholder: PropTypes.string
  };

  static defaultProps = {
    styles: undefined,
    calendarContainerProps: {},
    isGregorian: true,
    timePicker: true,
    showTodayButton: true,
    placeholder: ''
  };

  constructor(props) {
    super(props);
    // create a ref to store the textInput DOM element
    this.textInput = React.createRef();

    this.state = {
      isOpen: false,
      momentValue: this.props.defaultValue || null,
      inputValue: this.getValue(
        this.props.defaultValue,
        this.props.isGregorian,
        this.props.timePicker
      ),
      inputJalaaliFormat:
        this.props.inputJalaaliFormat || this.getInputFormat(false, this.props.timePicker),
      inputFormat: this.props.inputFormat || this.getInputFormat(true, this.props.timePicker),
      isGregorian: this.props.isGregorian,
      timePicker: this.props.timePicker,
      timePickerComponent: this.props.timePicker ? MyTimePicker : undefined
    };
  }

  getInputFormat(isGregorian, timePicker) {
    if (timePicker) return isGregorian ? 'YYYY/M/D hh:mm A' : 'jYYYY/jM/jD hh:mm A';
    return isGregorian ? 'YYYY/M/D' : 'jYYYY/jM/jD';
  }

  getValue(inputValue, isGregorian, timePicker) {
    if (!inputValue) return '';
    let { inputFormat } = this.state;
    let { inputJalaaliFormat } = this.state;
    if (!inputFormat) inputFormat = this.getInputFormat(isGregorian, timePicker);
    if (!inputJalaaliFormat) inputJalaaliFormat = this.getInputFormat(isGregorian, timePicker);

    return isGregorian
      ? inputValue.locale('es').format(inputFormat)
      : inputValue.locale('fa').format(inputJalaaliFormat);
  }

  setOpen = isOpen => {
    this.setState({ isOpen });

    if (this.props.onOpen) {
      this.props.onOpen(isOpen);
    }
  };

  UNSAFE_componentWillMount() {
    if (this.props.value) {
      this.setMomentValue(this.props.value);
    }
  }

  UNSAFE_componentWillReceiveProps(nextProps) {
    if ('value' in nextProps && nextProps.value !== this.props.value) {
      this.setMomentValue(nextProps.value);
    }

    if ('isGregorian' in nextProps && nextProps.isGregorian !== this.props.isGregorian) {
      const { inputFormat: nextPropsInputFormat } = nextProps;
      const { inputJalaaliFormat: nextPropsInputJalaaliFormat } = nextProps;

      this.setState({
        isGregorian: nextProps.isGregorian,
        inputValue: this.getValue(nextProps.value, nextProps.isGregorian, nextProps.timePicker),
        inputFormat: nextPropsInputFormat || this.state.inputFormat,
        inputJalaaliFormat: nextPropsInputJalaaliFormat || this.state.inputJalaaliFormat
      });
    }

    if ('timePicker' in nextProps && nextProps.timePicker !== this.props.timePicker) {
      this.setState({
        timePicker: nextProps.timePicker,
        timePickerComponent: this.props.timePicker ? MyTimePicker : undefined
      });
    }
  }

  toggleMode = () => {
    const isGregorian = !this.state.isGregorian;
    const { inputFormat: nextPropsInputFormat } = this.props;
    const { inputJalaaliFormat: nextPropsInputJalaaliFormat } = this.props;
    this.setState({
      isGregorian: isGregorian,
      inputValue: this.getValue(this.props.value, isGregorian, this.props.timePicker)
    });
  };

  setMomentValue(momentValue) {
    const { inputFormat, isGregorian, timePicker } = this.state;

    if (this.props.onChange) {
      this.props.onChange(momentValue);
    }

    const inputValue = this.getValue(momentValue, isGregorian, timePicker);

    this.setState({ momentValue, inputValue });
  }

  handleFocus = () => {
    this.setOpen(true);
  };

  handleClickOutsideCalendar() {
    this.setOpen(false);
  }

  toEnglishDigits(str) {
    if (!str) return str;
    const regex1 = /[\u0660-\u0669]/g;
    const regex2 = /[\u06f0-\u06f9]/g;
    return str
      .replace(regex1, function(c) {
        return c.charCodeAt(0) - 0x0660;
      })
      .replace(regex2, function(c) {
        return c.charCodeAt(0) - 0x06f0;
      });
  }

  toPersianDigits(str) {
    if (!str) return str;
    const regex = /[0-9]/g;
    const id = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
    return str.replace(regex, function(w) {
      return id[+w];
    });
  }

  handleSelectDay(selectedDay) {
    const { momentValue: oldValue } = this.state;
    let momentValue = selectedDay.clone();

    if (oldValue) {
      momentValue = momentValue.set({
        hour: oldValue.hours(),
        minute: oldValue.minutes(),
        second: oldValue.seconds()
      });
    }
    this.setOpen(false);
    this.setMomentValue(momentValue);
  }

  handleInputChange(event) {
    const { inputFormat, inputJalaaliFormat, isGregorian } = this.state;
    const inputValue = this.toEnglishDigits(event.target.value);
    const currentInputFormat = isGregorian ? inputFormat : inputJalaaliFormat;

    const momentValue = momentJalaali(inputValue, currentInputFormat);

    if (momentValue.isValid()) {
      this.setState({ momentValue });
      if (this.props.onChange) {
        this.props.onChange(momentValue);
      }
    }
    else if(inputValue === '') {
      if (this.props.onChange) {
        this.props.onChange('');
      }
    }

    this.setState({ inputValue });

    if (this.props.onInputChange) {
      this.props.onInputChange(event);
    }
  }

  handleInputClick() {
    if (!this.props.disabled) {
      this.setOpen(true);
    }
  }

  renderInput = ref => {
    const { isOpen, inputValue, isGregorian } = this.state;

    const className = classnames(this.props.className, {
      [outsideClickIgnoreClass]: isOpen
    });

    return (

        <input
          placeholder={this.props.placeholder}
          className={`datepicker-input ${className}`}
          type="text"
          ref={inst => {
            this.input = inst;
          }}
          onFocus={this.handleFocus.bind(this)}
          onChange={this.handleInputChange.bind(this)}
          onClick={this.handleInputClick.bind(this)}
          value={isGregorian ? inputValue : this.toPersianDigits(inputValue)}
          readOnly={this.props.inputReadOnly === true}
          disabled={this.props.disabled}
        />

    );
  };

  renderCalendar = ref => {
    const { momentValue, isGregorian, timePickerComponent: TimePicker } = this.state;
    const { onChange, min, max, defaultYear, defaultMonth, styles, calendarContainerProps, ranges } = this.props;

    return (

        <Calendar
          toggleMode={this.toggleMode}
          ranges={ranges}
          min={min}
          max={max}
          selectedDay={momentValue}
          defaultYear={defaultYear}
          defaultMonth={defaultMonth}
          onSelect={this.handleSelectDay.bind(this)}
          onClickOutside={this.handleClickOutsideCalendar.bind(this)}
          outsideClickIgnoreClass={outsideClickIgnoreClass}
          styles={styles}
          containerProps={calendarContainerProps}
          isGregorian={isGregorian}
          calendarClass={this.props.calendarClass ? this.props.calendarClass : ''}
          showToggleButton={this.props.showToggleButton}
          toggleButtonText={this.props.toggleButtonText}
          showTodayButton={this.props.showTodayButton}
          timePicker={
            TimePicker ? (
              <TimePicker
                outsideClickIgnoreClass={outsideClickIgnoreClass}
                isGregorian={isGregorian}
                min={min}
                max={max}
                momentValue={momentValue}
                setMomentValue={this.setMomentValue.bind(this)}
              />
            ) : null
          }
        />

    );
  };

  removeDate() {
    const { onChange } = this.props;
    if (onChange) {
      onChange('');
    }
    this.setState({
      input: '',
      inputValue: ''
    });
  }

  render() {
    const { isOpen } = this.state;

    return (
      <TetherComponent
        ref={tether => (this.tether = tether)}
        attachment={this.props.tetherAttachment ? this.props.tetherAttachment : 'top center'}
        constraints={[
          {
            to: 'window',
            attachment: 'together'
          }
        ]}
        offset="-10px -10px"
        onResize={() => this.tether && this.tether.position()}
        /* renderTarget: This is what the item will be tethered to, make sure to attach the ref */
        renderTarget={ref => this.renderInput(ref)}
        /* renderElement: If present, this item will be tethered to the the component returned by renderTarget */
        renderElement={ref => isOpen && this.renderCalendar(ref)}
      />
    );
  }
}
<|endoftext|>


<commit_before>const React = require('react');
const Radium = require('radium');
const moment = require('moment');

const Icon = require('./Icon');

const StyleConstants = require('../constants/Style');

class DatePicker extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      currentDate: null,
      selectedDate: moment.unix(this.props.defaultDate),
      showCalendar: false
    };
  }

  _handleDateSelect (date) {
    if (this.props.closeOnDateSelect) {
      this._handleBlur();
    }
    this.setState({
      selectedDate: moment.unix(date)
    });

    this.props.onDateSelect(date);
  }

  _handlePreviousClick () {
    const selectedDate = moment(this.state.selectedDate).locale(this.props.locale);
    let currentDate = this.state.currentDate ? this.state.currentDate.locale(this.props.locale) : selectedDate;

    currentDate = moment(currentDate.startOf('month').subtract(1, 'm'), this.props.format);

    this.setState({
      currentDate
    });
  }

  _handleNextClick () {
    const selectedDate = moment(this.state.selectedDate).locale(this.props.locale);
    let currentDate = this.state.currentDate ? this.state.currentDate.locale(this.props.locale) : selectedDate;

    currentDate = moment(currentDate.endOf('month').add(1, 'd'), this.props.format);

    this.setState({
      currentDate
    });
  }

  _renderMonthTable (currentDate, selectedDate) {
    const days = [];
    const startDate = moment(currentDate, this.props.format).startOf('month').startOf('week');
    const endDate = moment(currentDate, this.props.format).endOf('month').endOf('week');
    const minimumDate = this.props.minimumDate ? moment.unix(this.props.minimumDate) : null;

    while (startDate.isBefore(endDate)) {
      const isCurrentMonth = startDate.month() === currentDate.month();
      const isCurrentDay = startDate.format(this.props.format) === selectedDate.format(this.props.format);
      let day;

      if (startDate.isBefore(minimumDate)) {
        day = (

              {startDate.date()}

);
      } else {
        day = (

{startDate.date()}

);
      }

      if (this.props.showDayBorders) {
        day.props.style.push([styles.borderRight, styles.borderBottom]);
      }

      days.push(day);
      startDate.add(1, 'd');
    }

    return days;
  }

  _renderScrim (styles) {
    if (this.props.useScrim && this.state.showCalendar) {
      return (

      );
    }
  }

  _renderSelectedDate () {
    if (this.props.useInputForSelectedDate) {
      return (

          <input
            key='input'
            onClick={this._toggleCalendar.bind(this)}
            style={styles.input}
            type='text'
            value={moment(this.state.selectedDate).format(this.props.format)}
          />
          <Icon
            onClick={this._toggleCalendar.bind(this)}
            size='28px'
            style={styles.calendarIcon}
            type={this.state.showCalendar ? 'caret-up' : 'caret-down'}
          />

      );
    } else {
      return (

          {moment(this.state.selectedDate).format(this.props.format)}

      );
    }
  }

  _renderTitle (styles) {
    if (this.props.title) {
      return (

          {this.props.title}

      );
    }
  }

  _toggleCalendar () {
    this.setState({
      showCalendar: !this.state.showCalendar
    });
  }

  _handleBlur () {
    this.setState({
      showCalendar: false
    });
  }

  _renderCaret () {
    if (this.props.showCaret) {
      return (
        <Icon
          onClick={this._toggleCalendar.bind(this)}
          size='20px'
          style={styles.caret}
          type={this.state.showCalendar ? 'caret-up' : 'caret-down'}
        />
      );
    }
  }

  render () {
    const selectedDate = moment(this.state.selectedDate).locale(this.props.locale);
    const currentDate = this.state.currentDate ? this.state.currentDate.locale(this.props.locale) : selectedDate;

    return (

          {this._renderSelectedDate()}
          {this._renderCaret()}

          {this._renderTitle(styles)}

            <Icon
              onClick={this._handlePreviousClick.bind(this)}
              size='32px'
              style={[styles.navIcon, styles.navLeft, this.props.showDayBorders && styles.borderRight]}
              type='caret-left'
            />
            {currentDate.format('MMMM YYYY')}
            <Icon
              onClick={this._handleNextClick.bind(this)}
              size='32px'
              style={[styles.navIcon, styles.navRight, this.props.showDayBorders && styles.borderLeft]}
              type='caret-right'
            />

            {this._renderMonthTable(currentDate, selectedDate)}

        {this._renderScrim(styles)}

    );
  }
}

DatePicker.propTypes = {
  closeOnDateSelect: React.PropTypes.bool,
  defaultDate: React.PropTypes.number,
  format: React.PropTypes.string,
  locale: React.PropTypes.string,
  minimumDate: React.PropTypes.number,
  onDateSelect: React.PropTypes.func,
  scrimStyle: React.PropTypes.object,
  showCaret: React.PropTypes.bool,
  showDayBorders: React.PropTypes.bool,
  title: React.PropTypes.string,
  useInputForSelectedDate: React.PropTypes.bool,
  useScrim: React.PropTypes.bool
};

DatePicker.defaultProps = {
  closeOnDateSelect: false,
  defaultDate: moment().unix(),
  format: 'YYYY-MM-DD',
  locale: 'en',
  onDateSelect () {},
  scrimStyle: {},
  showCaret: true,
  showDayBorders: false,
  title: null,
  useInputForSelectedDate: true,
  useScrim: false
};

const styles = {
  caret: {
    color: '#CCCCCC',
    cursor: 'pointer',
    position: 'absolute',
    right: '0',
    top: '50%',
    transform: 'translateY(-50%)'
  },
  calendarDay: {
    color: '#DDDDDD',
    float: 'left',
    paddingBottom: '11%',
    position: 'relative',
    width: '13.5%'
  },
  borderBottom: {
    borderBottom: '#E5E5E5',
    borderBottomStyle: 'solid',
    borderBottomWidth: '1px'
  },
  borderRight: {
    borderRight: '#E5E5E5',
    borderRightStyle: 'solid',
    borderRightWidth: '1px'
  },
  borderLeft: {
    borderLeft: '#E5E5E5',
    borderLeftStyle: 'solid',
    borderLeftWidth: '1px'
  },
  calendarContainer: {
    width: '100%',
    padding: '0px 2px 10px 6px'
  },
  calendarDayContent: {
    borderRadius: '50%',
    height: '32px',
    left: '50%',
    position: 'absolute',
    top: '50%',
    transform: 'translateY(-50%) translateX(-50%)',
    width: '32px',

    ':hover': {
      backgroundColor: '#359BCF',
      color: '#FFFFFF',
      cursor: 'pointer'
    }
  },
  calendarDayText: {
    borderRadius: '100%',
    fontSize: StyleConstants.FontSize,
    fontWeight: 'normal',
    left: '50%',
    position: 'absolute',
    top: '50%',
    transform: 'translateY(-50%) translateX(-50%)'
  },
  calendarDayDisabled: {
    ':hover': {
      background: 'none',
      color: '#DDDDDD'
    }
  },
  calendarHeader: {
    color: '#606060',
    borderBottom: '#E5E5E5',
    borderBottomWidth: '1px',
    fontSize: '15px',
    fontWeight: 'normal',
    padding: '5px 0px 7px 0px',
    position: 'relative',
    textAlign: 'center',
    textTransform: 'none'
  },
  calendarIcon: {
    color: '#DDDDDD',
    position: 'absolute',
    right: '12.8px',
    top: '50%',
    transform: 'translateY(-50%)'
  },
  calendarShow: {
    display: 'block'
  },
  clearFix: {
    clear: 'both',
    marginBottom: '15px'
  },
  component: {
    backgroundColor: '#FFFFFF',
    color: '#000000',
    fontFamily: StyleConstants.FontFamily,
    fontSize: StyleConstants.FontSize,
    WebkitAppearance: 'none',
    width: '100%',

    '@media (max-width: 768px)': {
      fontSize: '8px'
    },

    ':focus': {
      boxShadow: 'none',
      outline: 'none'
    }
  },
  componentBottom: {
    backgroundColor: '#FFFFFF',
    borderBottomLeftRadius: '3px',
    borderBottomRightRadius: '3px',
    borderColor: '#E5E5E5',
    borderStyle: 'solid',
    borderWidth: '0 1px 1px 1px',
    boxShadow: StyleConstants.BoxShadow,
    boxSizing: 'border-box',
    display: 'none',
    maxWidth: '270px',
    padding: '0px 0px 0px 0px',
    margin: '0 0 40px 0',
    position: 'absolute',
    width: '100%',
    zIndex: 10
  },
  componentTop: {
    borderBottomWidth: '1px',
    borderColor: '#E5E5E5',
    borderRadius: '3px 3px 3px 3px',
    borderStyle: 'solid',
    borderWidth: '1px 1px 1px 1px',
    position: 'relative',
    padding: '5px 5px 5px 5px'
  },
  componentTopOpen: {
    borderBottomWidth: '0',
    borderRadius: '3px 3px 0 0'
  },
  currentDay: {
    backgroundColor: '#359BCF',
    color: '#FFFFFF'
  },
  currentMonth: {
    color: '#606060'
  },
  input: {
    backgroundColor: '#FFFFFF',
    border: 'none',
    fontSize: StyleConstants.FontSize,
    outline: 'none',
    paddingBottom: '10px',
    WebkitAppearance: 'none',
    width: '80%',

    ':focus': {
      border: 'none',
      boxShadow: 'none',
      outline: 'none'
    }
  },
  navIcon: {
    cursor: 'pointer'
  },
  navLeft: {
    position: 'absolute',
    left: '0',
    top: '50%',
    transform: 'translateY(-50%)'
  },
  navRight: {
    position: 'absolute',
    right: '0',
    top: '50%',
    transform: 'translateY(-50%)'
  },
  scrim: {
    position: 'fixed',
    zIndex: 9,
    top: 0,
    right: 0,
    bottom: 0,
    left: 0
  },
  selectedDate: {
    color: '#606060',
    cursor: 'pointer',
    fontSize: StyleConstants.FontSize,
    padding: '5px 0 5px 5px',
    verticalAlign: 'middle',
    width: '100%',

    ':hover': {
      color: '#359BCF'
    }
  },
  title: {
    backgroundColor: '#666666',
    color: '#f2f2f2',
    textAlign: 'center',
    padding: '7px 0px 7px 0px',
    fontSize: StyleConstants.FontSize,
    margin: '1px'
  }
};

module.exports = Radium(DatePicker);<commit_msg>added this.props.this<commit_after>const React = require('react');
const Radium = require('radium');
const moment = require('moment');

const Icon = require('./Icon');

const StyleConstants = require('../constants/Style');

class DatePicker extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      currentDate: null,
      selectedDate: moment.unix(this.props.defaultDate),
      showCalendar: false
    };
  }

  _handleDateSelect (date) {
    if (this.props.closeOnDateSelect) {
      this._handleBlur();
    }
    this.setState({
      selectedDate: moment.unix(date)
    });

    this.props.onDateSelect(date);
  }

  _handlePreviousClick () {
    const selectedDate = moment(this.state.selectedDate).locale(this.props.locale);
    let currentDate = this.state.currentDate ? this.state.currentDate.locale(this.props.locale) : selectedDate;

    currentDate = moment(currentDate.startOf('month').subtract(1, 'm'), this.props.format);

    this.setState({
      currentDate
    });
  }

  _handleNextClick () {
    const selectedDate = moment(this.state.selectedDate).locale(this.props.locale);
    let currentDate = this.state.currentDate ? this.state.currentDate.locale(this.props.locale) : selectedDate;

    currentDate = moment(currentDate.endOf('month').add(1, 'd'), this.props.format);

    this.setState({
      currentDate
    });
  }

  _renderMonthTable (currentDate, selectedDate) {
    const days = [];
    const startDate = moment(currentDate, this.props.format).startOf('month').startOf('week');
    const endDate = moment(currentDate, this.props.format).endOf('month').endOf('week');
    const minimumDate = this.props.minimumDate ? moment.unix(this.props.minimumDate) : null;

    while (startDate.isBefore(endDate)) {
      const isCurrentMonth = startDate.month() === currentDate.month();
      const isCurrentDay = startDate.format(this.props.format) === selectedDate.format(this.props.format);
      let day;

      if (startDate.isBefore(minimumDate)) {
        day = (

              {startDate.date()}

);
      } else {
        day = (

{startDate.date()}

);
      }

      if (this.props.showDayBorders) {
        day.props.style.push([styles.borderRight, styles.borderBottom]);
      }

      days.push(day);
      startDate.add(1, 'd');
    }

    return days;
  }

  _renderScrim (styles) {
    if (this.props.useScrim && this.state.showCalendar) {
      return (

      );
    }
  }

  _renderSelectedDate () {
    if (this.props.useInputForSelectedDate) {
      return (

          <input
            key='input'
            onClick={this._toggleCalendar.bind(this)}
            style={styles.input}
            type='text'
            value={moment(this.state.selectedDate).format(this.props.format)}
          />
          <Icon
            onClick={this._toggleCalendar.bind(this)}
            size='28px'
            style={styles.calendarIcon}
            type={this.state.showCalendar ? 'caret-up' : 'caret-down'}
          />

      );
    } else {
      return (

          {moment(this.state.selectedDate).format(this.props.format)}

      );
    }
  }

  _renderTitle (styles) {
    if (this.props.title) {
      return (

          {this.props.title}

      );
    }
  }

  _toggleCalendar () {
    this.setState({
      showCalendar: !this.state.showCalendar
    });
  }

  _handleBlur () {
    this.setState({
      showCalendar: false
    });
  }

  _renderCaret () {
    if (this.props.showCaret) {
      return (
        <Icon
          onClick={this._toggleCalendar.bind(this)}
          size='20px'
          style={styles.caret}
          type={this.state.showCalendar ? 'caret-up' : 'caret-down'}
        />
      );
    }
  }

  render () {
    const selectedDate = moment(this.state.selectedDate).locale(this.props.locale);
    const currentDate = this.state.currentDate ? this.state.currentDate.locale(this.props.locale) : selectedDate;

    return (

          {this._renderSelectedDate()}
          {this._renderCaret()}

          {this._renderTitle(styles)}

            <Icon
              onClick={this._handlePreviousClick.bind(this)}
              size='32px'
              style={[styles.navIcon, styles.navLeft, this.props.showDayBorders && styles.borderRight]}
              type='caret-left'
            />
            {currentDate.format('MMMM YYYY')}
            <Icon
              onClick={this._handleNextClick.bind(this)}
              size='32px'
              style={[styles.navIcon, styles.navRight, this.props.showDayBorders && styles.borderLeft]}
              type='caret-right'
            />

            {this._renderMonthTable(currentDate, selectedDate)}

        {this._renderScrim(styles)}

    );
  }
}

DatePicker.propTypes = {
  closeOnDateSelect: React.PropTypes.bool,
  defaultDate: React.PropTypes.number,
  format: React.PropTypes.string,
  locale: React.PropTypes.string,
  minimumDate: React.PropTypes.number,
  onDateSelect: React.PropTypes.func,
  scrimStyle: React.PropTypes.object,
  showCaret: React.PropTypes.bool,
  showDayBorders: React.PropTypes.bool,
  title: React.PropTypes.string,
  useInputForSelectedDate: React.PropTypes.bool,
  useScrim: React.PropTypes.bool
};

DatePicker.defaultProps = {
  closeOnDateSelect: false,
  defaultDate: moment().unix(),
  format: 'YYYY-MM-DD',
  locale: 'en',
  onDateSelect () {},
  scrimStyle: {},
  showCaret: true,
  showDayBorders: false,
  title: null,
  useInputForSelectedDate: true,
  useScrim: false
};

const styles = {
  caret: {
    color: '#CCCCCC',
    cursor: 'pointer',
    position: 'absolute',
    right: '0',
    top: '50%',
    transform: 'translateY(-50%)'
  },
  calendarDay: {
    color: '#DDDDDD',
    float: 'left',
    paddingBottom: '11%',
    position: 'relative',
    width: '13.5%'
  },
  borderBottom: {
    borderBottom: '#E5E5E5',
    borderBottomStyle: 'solid',
    borderBottomWidth: '1px'
  },
  borderRight: {
    borderRight: '#E5E5E5',
    borderRightStyle: 'solid',
    borderRightWidth: '1px'
  },
  borderLeft: {
    borderLeft: '#E5E5E5',
    borderLeftStyle: 'solid',
    borderLeftWidth: '1px'
  },
  calendarContainer: {
    width: '100%',
    padding: '0px 2px 10px 6px'
  },
  calendarDayContent: {
    borderRadius: '50%',
    height: '32px',
    left: '50%',
    position: 'absolute',
    top: '50%',
    transform: 'translateY(-50%) translateX(-50%)',
    width: '32px',

    ':hover': {
      backgroundColor: '#359BCF',
      color: '#FFFFFF',
      cursor: 'pointer'
    }
  },
  calendarDayText: {
    borderRadius: '100%',
    fontSize: StyleConstants.FontSize,
    fontWeight: 'normal',
    left: '50%',
    position: 'absolute',
    top: '50%',
    transform: 'translateY(-50%) translateX(-50%)'
  },
  calendarDayDisabled: {
    ':hover': {
      background: 'none',
      color: '#DDDDDD'
    }
  },
  calendarHeader: {
    color: '#606060',
    borderBottom: '#E5E5E5',
    borderBottomWidth: '1px',
    fontSize: '15px',
    fontWeight: 'normal',
    padding: '5px 0px 7px 0px',
    position: 'relative',
    textAlign: 'center',
    textTransform: 'none'
  },
  calendarIcon: {
    color: '#DDDDDD',
    position: 'absolute',
    right: '12.8px',
    top: '50%',
    transform: 'translateY(-50%)'
  },
  calendarShow: {
    display: 'block'
  },
  clearFix: {
    clear: 'both',
    marginBottom: '15px'
  },
  component: {
    backgroundColor: '#FFFFFF',
    color: '#000000',
    fontFamily: StyleConstants.FontFamily,
    fontSize: StyleConstants.FontSize,
    WebkitAppearance: 'none',
    width: '100%',

    '@media (max-width: 768px)': {
      fontSize: '8px'
    },

    ':focus': {
      boxShadow: 'none',
      outline: 'none'
    }
  },
  componentBottom: {
    backgroundColor: '#FFFFFF',
    borderBottomLeftRadius: '3px',
    borderBottomRightRadius: '3px',
    borderColor: '#E5E5E5',
    borderStyle: 'solid',
    borderWidth: '0 1px 1px 1px',
    boxShadow: StyleConstants.BoxShadow,
    boxSizing: 'border-box',
    display: 'none',
    maxWidth: '270px',
    padding: '0px 0px 0px 0px',
    margin: '0 0 40px 0',
    position: 'absolute',
    width: '100%',
    zIndex: 10
  },
  componentTop: {
    borderBottomWidth: '1px',
    borderColor: '#E5E5E5',
    borderRadius: '3px 3px 3px 3px',
    borderStyle: 'solid',
    borderWidth: '1px 1px 1px 1px',
    position: 'relative',
    padding: '5px 5px 5px 5px'
  },
  componentTopOpen: {
    borderBottomWidth: '0',
    borderRadius: '3px 3px 0 0'
  },
  currentDay: {
    backgroundColor: '#359BCF',
    color: '#FFFFFF'
  },
  currentMonth: {
    color: '#606060'
  },
  input: {
    backgroundColor: '#FFFFFF',
    border: 'none',
    fontSize: StyleConstants.FontSize,
    outline: 'none',
    paddingBottom: '10px',
    WebkitAppearance: 'none',
    width: '80%',

    ':focus': {
      border: 'none',
      boxShadow: 'none',
      outline: 'none'
    }
  },
  navIcon: {
    cursor: 'pointer'
  },
  navLeft: {
    position: 'absolute',
    left: '0',
    top: '50%',
    transform: 'translateY(-50%)'
  },
  navRight: {
    position: 'absolute',
    right: '0',
    top: '50%',
    transform: 'translateY(-50%)'
  },
  scrim: {
    position: 'fixed',
    zIndex: 9,
    top: 0,
    right: 0,
    bottom: 0,
    left: 0
  },
  selectedDate: {
    color: '#606060',
    cursor: 'pointer',
    fontSize: StyleConstants.FontSize,
    padding: '5px 0 5px 5px',
    verticalAlign: 'middle',
    width: '100%',

    ':hover': {
      color: '#359BCF'
    }
  },
  title: {
    backgroundColor: '#666666',
    color: '#f2f2f2',
    textAlign: 'center',
    padding: '7px 0px 7px 0px',
    fontSize: StyleConstants.FontSize,
    margin: '1px'
  }
};

module.exports = Radium(DatePicker);<|endoftext|>


<commit_before>import React    from 'react';
import { Link } from 'react-router';

export default class Navigation extends React.Component {
  static propTypes = {
    history: React.PropTypes.object.isRequired
  }
  constructor(props) {
    super(props);
    this.state = {
      navigation: [
        {route: '/',       name: 'home'},
        {route: '/drincs', name: 'drincs'},
        {route: '/orders', name: 'bectellungen'}
      ]
    };
  }

  render() {
    return (

            getra:nce bestellung

              {this.state.navigation.map((element) =>
<Link to={element.route}>{element.name}</Link>
)}

    );
  }
}
<commit_msg>navigation: set key, header also Link<commit_after>import React    from 'react';
import { Link } from 'react-router';

export default class Navigation extends React.Component {
  static propTypes = {
    history: React.PropTypes.object.isRequired
  }
  constructor(props) {
    super(props);
    this.state = {
      navigation: [
        {route: '/',       name: 'home'},
        {route: '/drincs', name: 'drincs'},
        {route: '/orders', name: 'bectellungen'}
      ]
    };
  }

  render() {
    return (

            <Link to="/" className="navbar-brand">getra:nce</Link>

              {this.state.navigation.map((element, index) =>
<Link to={element.route}>{element.name}</Link>
)}

    );
  }
}
<|endoftext|>