ProteusThemes support working hours widget. Made with moment.js
<html> | |
<head> | |
<title>support opening time</title> | |
<!-- deps: jquery, underscore.js, moment.js --> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.4.0/moment.min.js"></script> | |
<script> | |
jQuery( document ).ready( function ( $ ) { | |
/** | |
* Header widget for the official online/offline and opening hours | |
*/ | |
(function () { | |
var SupportStatus = function () { | |
/** | |
* Ultimate config object | |
* @type {Object} | |
*/ | |
this.config = { | |
workingDays: [1, 2, 3, 4, 5], // 0 = sun, 1 = mon ... 6 = sat | |
workingHours: { // 24h format | |
start: 8, | |
end: 15 | |
}, | |
tmpls: { | |
status: _.template( 'Our <strong>support staff</strong> is currently <span class="support-status-badge is-<%- status %>"><%- status %></span>.' ), | |
onlineAgain: _.template( 'We will be online again <strong><%- timeToOnline %></strong>.' ), | |
yourOurTime: _.template( 'Your time: <strong><%- yourTime %></strong> | Our time: <strong><%- ourTime %></strong>' ), | |
officialHour: _.template( 'Official hours: <strong><%- workingRange %></strong>.' ), | |
}, | |
}; | |
// set local pointer to moment() | |
this.moment = moment; | |
// alias | |
this.tmpls = this.config.tmpls; | |
/** | |
* Set times on init and moment objects for the working hours | |
*/ | |
this.updateTimes(); | |
return this; | |
}; | |
_.extend( SupportStatus.prototype, { | |
/** | |
* Parse HTML from underscores templates, defined in the this.config.tmpls | |
* @return {string} html | |
*/ | |
parse: function () { | |
var htmlLines = []; | |
htmlLines.push( this.tmpls.status( { status: this.statusBadgeText() } ) ); | |
if ( ! this.isWorkingTime() ) { // only display outside working hours | |
htmlLines.push( this.tmpls.onlineAgain( { timeToOnline: this.getTimeToOnline() } ) ); | |
} | |
htmlLines.push( this.tmpls.officialHour( { workingRange: this.officialHoursText() } ) ); | |
htmlLines.push( this.tmpls.yourOurTime( { | |
yourTime: this.clientTime.format( 'ddd, h:mm a' ), | |
ourTime: this.supportTime.format( 'ddd, h:mm a' ), | |
} ) ); | |
return htmlLines.join( '<br />' ); | |
}, | |
/** | |
* Update client and support time anew | |
* @return this | |
*/ | |
updateTimes: function () { | |
this.clientTime = this.moment(); | |
this.supportTime = this.moment().utc().zone( this.clientTime.isDST() ? -120 : -60 ); | |
// can use this in moment v2.10.3+ | |
// this.supportTime = this.moment().utc().utcOffset( this.clientTime.isDST() ? 120 : 60 ); | |
this.workingHours = this.setWorkingHours(); | |
return this; | |
}, | |
/** | |
* Check if it is a working day | |
* @return {Boolean} | |
*/ | |
isWorkingDay: function () { | |
return _.contains( this.config.workingDays, this.supportTime.day() ); | |
}, | |
/** | |
* Check if support team is online now = time now is between end and start | |
* @return {Boolean} | |
*/ | |
isWorkingTime: function () { | |
return ( this.supportTime.isAfter( this.workingHours.start ) && this.supportTime.isBefore( this.workingHours.end ) ); | |
// can use this in moment v2.10.3+ | |
// return this.supportTime.isBetween( this.workingHours.start, this.workingHours.end ); | |
}, | |
/** | |
* Return support team status based on the working time | |
* @return {string} online/offline | |
*/ | |
statusBadgeText: function () { | |
if ( this.isWorkingTime() ) { | |
return 'online'; | |
} | |
return 'offline'; | |
}, | |
/** | |
* Return the start and end working hours as moment objects. | |
* If current time is a working day before the support ended shift start/end represent the points in time for the current day, | |
* otherwise for the next working day. | |
* @return {object} start/end | |
*/ | |
setWorkingHours: function () { | |
if ( ! this.isWorkingDay() || this.supportTime.hour() >= this.config.workingHours.end ) { // set to the next working day | |
var nextWorkingDay = this.getNextWorkingDay( this.supportTime.clone() ); | |
return { | |
start: nextWorkingDay.clone().hour( this.config.workingHours.start ).startOf( 'hour' ), | |
end: nextWorkingDay.clone().hour( this.config.workingHours.end ).startOf( 'hour' ) | |
}; | |
} | |
else { // start/end in the same day | |
return { | |
start: this.supportTime.clone().hour( this.config.workingHours.start ).startOf( 'hour' ), | |
end: this.supportTime.clone().hour( this.config.workingHours.end ).startOf( 'hour' ) | |
}; | |
} | |
}, | |
/** | |
* Get the next working day, based on the config. | |
* @return {moment} | |
*/ | |
getNextWorkingDay: function ( fromDay ) { | |
var nextDay = fromDay.add( 1, 'days' ); | |
if ( _.contains( this.config.workingDays, nextDay.day() ) ) { | |
return nextDay; | |
} | |
else { | |
return this.getNextWorkingDay( nextDay ); | |
} | |
}, | |
/** | |
* Returns the human readable text when we're online again in format: in 3 hours | |
* @return {string} | |
*/ | |
getTimeToOnline: function () { | |
return this.workingHours.start.from( this.clientTime ); | |
// can use this in moment v2.10.3+ | |
// return this.clientTime.to( this.workingHours.start ); | |
}, | |
/** | |
* Display the official working hours based on the config. | |
* Calling this function only once and caching output. | |
* @return {string} | |
*/ | |
officialHoursText: _.once( function () { | |
var str = _.template( '<%- dayStart %>-<%- dayEnd %> / <%- hourStart %>-<%- hourEnd %> (GMT+<%- tz %>)' ); | |
return str( { | |
dayStart: this.moment().day( _.min( this.config.workingDays ) ).format( 'ddd' ), | |
dayEnd: this.moment().day( _.max( this.config.workingDays ) ).format( 'ddd' ), | |
hourStart: this.moment().hour( this.config.workingHours.start ).startOf( 'hour' ).format( 'ha' ), | |
hourEnd: this.moment().hour( this.config.workingHours.end ).startOf( 'hour' ).format( 'ha' ), | |
tz: this.moment().isDST() ? 2 : 1, | |
} ); | |
} ), | |
} ); | |
// only instance of the class above | |
var supportStatus = new SupportStatus(); | |
var updateSupportHTML = function () { | |
$( '#js-support-time' ).html( supportStatus.updateTimes().parse() ); | |
}; | |
updateSupportHTML(); | |
// update every 30 seconds | |
setInterval( updateSupportHTML, 30*1000 ); | |
})(); | |
} ); | |
</script> | |
</head> | |
<body> | |
<div id="js-support-time"></div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment