RestrictedRadioButtons.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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 'underscore'
  19. import React from 'react'
  20. import PropTypes from 'prop-types'
  21. import ReactDOM from 'react-dom'
  22. import I18n from 'i18n!restrict_student_access'
  23. import $ from 'jquery'
  24. import customPropTypes from 'compiled/react_files/modules/customPropTypes'
  25. import Folder from 'compiled/models/Folder'
  26. import 'jquery.instructure_date_and_time'
  27. var RestrictedRadioButtons = React.createClass({
  28. propTypes: {
  29. models: PropTypes.arrayOf(customPropTypes.filesystemObject).isRequired,
  30. radioStateChange: PropTypes.func
  31. },
  32. permissionOptions: [{
  33. ref: 'publishInput',
  34. text: I18n.t('Publish'),
  35. selectedOptionKey: 'published',
  36. iconClasses: 'icon-publish icon-Solid RestrictedRadioButtons__publish_icon',
  37. onChange () {
  38. this.updateBtnEnable();
  39. this.setState({selectedOption: 'published'});
  40. }
  41. }, {
  42. ref: 'unpublishInput',
  43. text: I18n.t('Unpublish'),
  44. selectedOptionKey: 'unpublished',
  45. iconClasses: 'icon-unpublish RestrictedRadioButtons__unpublish_icon',
  46. onChange () {
  47. this.updateBtnEnable();
  48. this.setState({selectedOption: 'unpublished'});
  49. }
  50. }, {
  51. ref: 'permissionsInput',
  52. text: I18n.t('Restricted Access'),
  53. selectedOptionKey: ['link_only', 'date_range'],
  54. iconClasses: 'icon-cloud-lock RestrictedRadioButtons__icon-cloud-lock',
  55. onChange () {
  56. var selectedOption = (this.state.unlock_at) ? 'date_range' : 'link_only';
  57. this.updateBtnEnable();
  58. this.setState({selectedOption});
  59. }
  60. }],
  61. restrictedOptions: [{
  62. ref: 'link_only',
  63. selectedOptionKey: 'link_only',
  64. getText () {
  65. if (this.allFolders()) {
  66. return I18n.t('Hidden, files inside will be available with links.');
  67. } else if (this.props.models.length > 1 && this.anyFolders()) {
  68. return I18n.t('Files and folder contents only available to students with link. Not visible in student files.');
  69. } else {
  70. return I18n.t('Only available to students with link. Not visible in student files.');
  71. }
  72. }
  73. }, {
  74. ref: 'dateRange',
  75. selectedOptionKey: 'date_range',
  76. getText () { return I18n.t('Schedule student availability'); }
  77. }],
  78. getInitialState() {
  79. var allAreEqual, initialState, permissionAttributes;
  80. permissionAttributes = ['hidden', 'locked', 'lock_at', 'unlock_at'];
  81. initialState = {};
  82. allAreEqual = this.props.models.every((model) => {
  83. return permissionAttributes.every((attribute) => {
  84. return this.props.models[0].get(attribute) === model.get(attribute) || (!this.props.models[0].get(attribute) && !model.get(attribute));
  85. });
  86. });
  87. if (allAreEqual) {
  88. initialState = this.props.models[0].pick(permissionAttributes);
  89. if (initialState.locked) {
  90. initialState.selectedOption = 'unpublished'
  91. } else {
  92. if (initialState.lock_at || initialState.unlock_at) {
  93. initialState.selectedOption = 'date_range'
  94. } else if (initialState.hidden) {
  95. initialState.selectedOption = 'link_only'
  96. } else {
  97. initialState.selectedOption = 'published'
  98. }
  99. };
  100. }
  101. return initialState;
  102. },
  103. componentDidMount: function () {
  104. return $([
  105. ReactDOM.findDOMNode(this.refs.unlock_at),
  106. ReactDOM.findDOMNode(this.refs.lock_at)]).datetime_field();
  107. },
  108. extractFormValues: function () {
  109. return {
  110. hidden: this.state.selectedOption === 'link_only',
  111. unlock_at: this.state.selectedOption === 'date_range' && $(ReactDOM.findDOMNode(this.refs.unlock_at)).data('unfudged-date') || '',
  112. lock_at: this.state.selectedOption === 'date_range' && $(ReactDOM.findDOMNode(this.refs.lock_at)).data('unfudged-date') || '',
  113. locked: this.state.selectedOption === 'unpublished'
  114. };
  115. },
  116. allFolders: function () {
  117. return this.props.models.every(function(model) {
  118. return model instanceof Folder;
  119. });
  120. },
  121. /*
  122. # Returns true if all the models passed in are folders.
  123. */
  124. anyFolders: function () {
  125. return this.props.models.filter(function(model) {
  126. return model instanceof Folder;
  127. }).length;
  128. },
  129. updateBtnEnable: function () {
  130. if (this.props.radioStateChange) {
  131. this.props.radioStateChange();
  132. };
  133. },
  134. isPermissionChecked: function (option) {
  135. return (this.state.selectedOption === option.selectedOptionKey) ||
  136. _.contains(option.selectedOptionKey, this.state.selectedOption);
  137. },
  138. renderPermissionOptions: function () {
  139. return this.permissionOptions.map((option, index) => {
  140. return (
  141. <div className='radio' key={index}>
  142. <label>
  143. <input
  144. ref={option.ref}
  145. type='radio'
  146. name='permissions'
  147. checked={this.isPermissionChecked(option)}
  148. onChange={option.onChange.bind(this)}
  149. />
  150. <i className={option.iconClasses} aria-hidden={true}></i>
  151. {option.text}
  152. </label>
  153. </div>
  154. );
  155. });
  156. },
  157. renderRestrictedAccessOptions: function () {
  158. if (this.state.selectedOption !== 'link_only' && this.state.selectedOption !== 'date_range') {
  159. return null;
  160. }
  161. return (
  162. <div style={{marginLeft: '20px'}}>
  163. {
  164. this.restrictedOptions.map((option, index) => {
  165. return (
  166. <div className='radio' key={index}>
  167. <label>
  168. <input
  169. ref={option.ref}
  170. type='radio'
  171. name='restrict_options'
  172. checked={this.state.selectedOption === option.selectedOptionKey}
  173. onChange={() => { this.setState({selectedOption: option.selectedOptionKey});}}
  174. />
  175. {option.getText.bind(this)()}
  176. </label>
  177. </div>
  178. );
  179. })
  180. }
  181. </div>
  182. );
  183. },
  184. renderDatePickers: function () {
  185. var styleObj = {};
  186. if (this.state.selectedOption !== 'date_range') {
  187. styleObj.visibility = 'hidden';
  188. }
  189. return (
  190. <div style={styleObj}>
  191. <label className='control-label dialog-adapter-form-calendar-label'>
  192. {I18n.t('Available From')}
  193. </label>
  194. <div className='dateSelectInputContainer controls'>
  195. <input
  196. ref='unlock_at'
  197. defaultValue={(this.state.unlock_at) ? $.datetimeString(this.state.unlock_at) : ''}
  198. className='form-control dateSelectInput'
  199. type='text'
  200. aria-label={I18n.t('Available From Date')}
  201. />
  202. </div>
  203. <div>
  204. <label className='control-label dialog-adapter-form-calendar-label'>
  205. {I18n.t('Available Until')}
  206. </label>
  207. <div className='dateSelectInputContainer controls'>
  208. <input
  209. id='lockDate'
  210. ref='lock_at'
  211. defaultValue={(this.state.lock_at) ? $.datetimeString(this.state.lock_at) : ''}
  212. className='form-control dateSelectInput'
  213. type='text'
  214. aria-label={I18n.t('Available Until Date')}
  215. />
  216. </div>
  217. </div>
  218. </div>
  219. );
  220. },
  221. renderRestrictedRadioButtons: function (options) {
  222. return (
  223. <div>
  224. {this.renderPermissionOptions()}
  225. {this.renderRestrictedAccessOptions()}
  226. {this.renderDatePickers()}
  227. </div>
  228. );
  229. },
  230. render: function () {
  231. return (
  232. <div>
  233. {this.renderRestrictedRadioButtons()}
  234. </div>
  235. );
  236. }
  237. });
  238. export default RestrictedRadioButtons