DueDateCalendarPicker.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * Copyright (C) 2015 - present Instructure, Inc.
  3. *
  4. * This file is part of Canvas.
  5. *
  6. * Canvas is free software: you can redistribute it and/or modify it under
  7. * the terms of the GNU Affero General Public License as published by the Free
  8. * Software Foundation, version 3 of the License.
  9. *
  10. * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
  11. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. * details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License along
  16. * with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. import $ from 'jquery'
  19. import React from 'react'
  20. import PropTypes from 'prop-types'
  21. import accessibleDateFormat from 'jsx/shared/helpers/accessibleDateFormat'
  22. import tz from 'timezone'
  23. import 'jquery.instructure_forms'
  24. import cx from 'classnames'
  25. const { string, func, bool, instanceOf, oneOfType } = PropTypes;
  26. var DueDateCalendarPicker = React.createClass({
  27. propTypes: {
  28. dateType: string.isRequired,
  29. handleUpdate: func.isRequired,
  30. rowKey: string.isRequired,
  31. labelledBy: string.isRequired,
  32. inputClasses: string.isRequired,
  33. disabled: bool.isRequired,
  34. isFancyMidnight: bool.isRequired,
  35. dateValue: oneOfType([instanceOf(Date), string]).isRequired,
  36. labelText: string.isRequired,
  37. readonly: bool
  38. },
  39. getDefaultProps () {
  40. return {
  41. readonly: false
  42. };
  43. },
  44. // ---------------
  45. // Lifecycle
  46. // ---------------
  47. componentDidMount() {
  48. var dateInput = this.refs.dateInput
  49. $(dateInput).datetime_field().change( (e) => {
  50. var trimmedInput = $.trim(e.target.value)
  51. var newDate = $(dateInput).data('unfudged-date')
  52. newDate = (trimmedInput === "") ? null : newDate
  53. newDate = this.changeToFancyMidnightIfNeeded(newDate)
  54. this.props.handleUpdate(newDate)
  55. })
  56. },
  57. // ensure jquery UI updates (as react doesn't know about it)
  58. componentDidUpdate() {
  59. var dateInput = this.refs.dateInput
  60. $(dateInput).val(this.formattedDate())
  61. },
  62. changeToFancyMidnightIfNeeded(date) {
  63. if (this.props.isFancyMidnight && tz.isMidnight(date)) {
  64. return tz.changeToTheSecondBeforeMidnight(date);
  65. }
  66. return date;
  67. },
  68. // ---------------
  69. // Rendering
  70. // ---------------
  71. formattedDate() {
  72. return $.datetimeString(this.props.dateValue)
  73. },
  74. wrapperClassName() {
  75. return this.props.dateType == "due_at" ?
  76. "DueDateInput__Container" :
  77. "DueDateRow__LockUnlockInput"
  78. },
  79. render() {
  80. if (this.props.disabled || this.props.readonly) {
  81. const className = cx('ic-Form-control', {readonly: this.props.readonly});
  82. return (
  83. <div className={className}>
  84. <label className="ic-Label" htmlFor={this.props.dateType}>{this.props.labelText}</label>
  85. <div className="ic-Input-group">
  86. <input
  87. id={this.props.dateType}
  88. readOnly
  89. type="text"
  90. className={`ic-Input ${this.props.inputClasses}`}
  91. defaultValue={this.formattedDate()}
  92. />
  93. {
  94. this.props.readonly ? null :
  95. <div className="ic-Input-group__add-on" role="presentation" aria-hidden="true" tabIndex="-1">
  96. <button className="Button Button--icon-action disabled" aria-disabled="true" type="button">
  97. <i className="icon-calendar-month" role="presentation" />
  98. </button>
  99. </div>
  100. }
  101. </div>
  102. </div>
  103. );
  104. }
  105. return (
  106. <div>
  107. <label
  108. id={this.props.labelledBy}
  109. className="Date__label"
  110. >{this.props.labelText}</label>
  111. <div
  112. ref="datePickerWrapper"
  113. className={this.wrapperClassName()}
  114. >
  115. <input
  116. type = "text"
  117. ref = "dateInput"
  118. title = {accessibleDateFormat()}
  119. data-tooltip = ""
  120. className = {this.props.inputClasses}
  121. aria-labelledby = {this.props.labelledBy}
  122. data-row-key = {this.props.rowKey}
  123. data-date-type = {this.props.dateType}
  124. defaultValue = {this.formattedDate()}
  125. />
  126. </div>
  127. </div>
  128. )
  129. }
  130. });
  131. export default DueDateCalendarPicker