Skip to content

Commit

Permalink
feat: change studio schedule datetime inputs to user timezone
Browse files Browse the repository at this point in the history
(cherry picked from commit ed4c7cc)
  • Loading branch information
kaustavb12 authored and 0x29a committed Oct 5, 2022
1 parent 216a206 commit 1c228db
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 2 deletions.
7 changes: 7 additions & 0 deletions cms/djangoapps/contentstore/views/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
from openedx.core.djangoapps.credit.tasks import update_credit_course_requirements
from openedx.core.djangoapps.models.course_details import CourseDetails
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.user_api.models import UserPreference
from openedx.core.djangolib.js_utils import dump_js_escaped_json
from openedx.core.lib.course_tabs import CourseTabPluginManager
from openedx.core.lib.courses import course_image_url
Expand Down Expand Up @@ -1214,6 +1215,12 @@ def settings_handler(request, course_key_string): # lint-amnesty, pylint: disab
elif 'application/json' in request.META.get('HTTP_ACCEPT', ''):
if request.method == 'GET':
course_details = CourseDetails.fetch(course_key)

# Fetch the prefered timezone setup by the user
# and pass it as part of Json response
user_timezone = UserPreference.get_value(request.user, 'time_zone')
course_details.user_timezone = user_timezone

return JsonResponse(
course_details,
# encoder serializes dates, old locations, and instances
Expand Down
1 change: 1 addition & 0 deletions cms/static/cms/js/spec/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
'jquery.simulate': 'xmodule_js/common_static/js/vendor/jquery.simulate',
'datepair': 'xmodule_js/common_static/js/vendor/timepicker/datepair',
'date': 'xmodule_js/common_static/js/vendor/date',
'moment-timezone': 'common/js/vendor/moment-timezone-with-data',
moment: 'common/js/vendor/moment-with-locales',
'text': 'xmodule_js/common_static/js/vendor/requirejs/text',
'underscore': 'common/js/vendor/underscore',
Expand Down
61 changes: 59 additions & 2 deletions cms/static/js/utils/date_utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
define(['jquery', 'date', 'js/utils/change_on_enter', 'jquery.ui', 'jquery.timepicker'],
function($, date, TriggerChangeEventOnEnter) {
define(['jquery', 'date', 'js/utils/change_on_enter', 'moment-timezone', 'jquery.ui', 'jquery.timepicker'],
function($, date, TriggerChangeEventOnEnter, moment) {
'use strict';

function getDate(datepickerInput, timepickerInput) {
Expand Down Expand Up @@ -67,14 +67,54 @@ function($, date, TriggerChangeEventOnEnter) {
return obj;
}

/**
* Calculates the utc offset in miliseconds for given
* timezone and subtracts it from given localized time
* to get time in UTC
*
* @param {Date} localTime JS Date object in Local Time
* @param {string} timezone IANA timezone name ex. "Australia/Brisbane"
* @returns JS Date object in UTC
*/
function convertLocalizedDateToUTC(localTime, timezone) {
const localTimeMS = localTime.getTime();
const utcOffset = moment.tz(localTime, timezone)._offset;
return new Date(localTimeMS - (utcOffset * 60 *1000));
}

/**
* Returns the timezone abbreviation for given
* timezone name
*
* @param {string} timezone IANA timezone name ex. "Australia/Brisbane"
* @returns Timezone abbreviation ex. "AEST"
*/
function getTZAbbreviation(timezone) {
return moment(new Date()).tz(timezone).format('z');
}

/**
* Converts the given datetime string from UTC to localized time
*
* @param {string} utcDateTime JS Date object with UTC datetime
* @param {string} timezone IANA timezone name ex. "Australia/Brisbane"
* @returns Formatted datetime string with localized timezone
*/
function getLocalizedCurrentDate(utcDateTime, timezone) {
const localDateTime = moment(utcDateTime).tz(timezone);
return localDateTime.format('YYYY-MM-DDTHH[:]mm[:]ss');
}

function setupDatePicker(fieldName, view, index) {
var cacheModel;
var div;
var datefield;
var timefield;
var tzfield;
var cacheview;
var setfield;
var currentDate;
var timezone;
if (typeof index !== 'undefined' && view.hasOwnProperty('collection')) {
cacheModel = view.collection.models[index];
div = view.$el.find('#' + view.collectionSelector(cacheModel.cid));
Expand All @@ -84,10 +124,18 @@ function($, date, TriggerChangeEventOnEnter) {
}
datefield = $(div).find('input.date');
timefield = $(div).find('input.time');
tzfield = $(div).find('span.timezone');
cacheview = view;

timezone = cacheModel.get('user_timezone');

setfield = function(event) {
var newVal = getDate(datefield, timefield);

if (timezone) {
newVal = convertLocalizedDateToUTC(newVal, timezone);
}

// Setting to null clears the time as well, as date and time are linked.
// Note also that the validation logic prevents us from clearing the start date
// (start date is required by the back end).
Expand All @@ -109,8 +157,17 @@ function($, date, TriggerChangeEventOnEnter) {
if (cacheModel) {
currentDate = cacheModel.get(fieldName);
}

if (timezone) {
const tz = getTZAbbreviation(timezone);
$(tzfield).text("("+tz+")");
}

// timepicker doesn't let us set null, so check that we have a time
if (currentDate) {
if (timezone) {
currentDate = getLocalizedCurrentDate(currentDate, timezone);
}
setDate(datefield, timefield, currentDate);
} else {
// but reset fields either way
Expand Down

0 comments on commit 1c228db

Please sign in to comment.