TotalGradeColumnHeader.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Copyright (C) 2017 - 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 React from 'react';
  19. import { bool, func, shape, string } from 'prop-types';
  20. import IconMoreSolid from 'instructure-icons/lib/Solid/IconMoreSolid';
  21. import {
  22. MenuItem,
  23. MenuItemFlyout,
  24. MenuItemGroup,
  25. MenuItemSeparator
  26. } from 'instructure-ui/lib/components/Menu';
  27. import PopoverMenu from 'instructure-ui/lib/components/PopoverMenu';
  28. import Typography from 'instructure-ui/lib/components/Typography';
  29. import I18n from 'i18n!gradebook';
  30. import ScreenReaderContent from 'instructure-ui/lib/components/ScreenReaderContent';
  31. import ColumnHeader from 'jsx/gradezilla/default_gradebook/components/ColumnHeader';
  32. function renderTrigger (menuShown, ref) {
  33. const classes = `Gradebook__ColumnHeaderAction ${menuShown ? 'menuShown' : ''}`;
  34. return (
  35. <span ref={ref} className={classes}>
  36. <Typography weight="bold" fontStyle="normal" size="large" color="brand">
  37. <IconMoreSolid className="rotated" title={I18n.t('Total Options')} />
  38. </Typography>
  39. </span>
  40. );
  41. }
  42. class TotalGradeColumnHeader extends ColumnHeader {
  43. static propTypes = {
  44. sortBySetting: shape({
  45. direction: string.isRequired,
  46. disabled: bool.isRequired,
  47. isSortColumn: bool.isRequired,
  48. onSortByGradeAscending: func.isRequired,
  49. onSortByGradeDescending: func.isRequired,
  50. settingKey: string.isRequired
  51. }).isRequired,
  52. gradeDisplay: shape({
  53. currentDisplay: string.isRequired,
  54. onSelect: func.isRequired,
  55. disabled: bool.isRequired,
  56. hidden: bool.isRequired
  57. }).isRequired,
  58. position: shape({
  59. isInFront: bool.isRequired,
  60. isInBack: bool.isRequired,
  61. onMoveToFront: func.isRequired,
  62. onMoveToBack: func.isRequired
  63. }).isRequired,
  64. onMenuClose: func.isRequired,
  65. grabFocus: bool,
  66. ...ColumnHeader.propTypes
  67. };
  68. static defaultProps = {
  69. grabFocus: false,
  70. ...ColumnHeader.defaultProps
  71. };
  72. state = { menuShown: false, skipFocusOnClose: false };
  73. switchGradeDisplay = () => { this.invokeAndSkipFocus(this.props.gradeDisplay) };
  74. invokeAndSkipFocus (action) {
  75. this.setState({ skipFocusOnClose: true });
  76. action.onSelect(this.focusAtEnd);
  77. }
  78. componentDidMount () {
  79. if (this.props.grabFocus) {
  80. this.focusAtEnd();
  81. }
  82. }
  83. render () {
  84. const { sortBySetting, gradeDisplay, position } = this.props;
  85. const selectedSortSetting = sortBySetting.isSortColumn && sortBySetting.settingKey;
  86. const displayAsPoints = gradeDisplay.currentDisplay === 'points';
  87. const showSeparator = !gradeDisplay.hidden;
  88. const nowrapStyle = {
  89. whiteSpace: 'nowrap'
  90. };
  91. const menuShown = this.state.menuShown;
  92. return (
  93. <div className="Gradebook__ColumnHeaderContent">
  94. <span className="Gradebook__ColumnHeaderDetail">
  95. <Typography weight="normal" fontStyle="normal" size="small">
  96. { I18n.t('Total') }
  97. </Typography>
  98. </span>
  99. <PopoverMenu
  100. ref={this.bindOptionsMenu}
  101. contentRef={this.bindOptionsMenuContent}
  102. shouldFocusTriggerOnClose={false}
  103. trigger={renderTrigger(menuShown, this.bindOptionsMenuTrigger)}
  104. onToggle={this.onToggle}
  105. onClose={this.props.onMenuClose}
  106. >
  107. <MenuItemFlyout contentRef={this.bindSortByMenuContent} label={I18n.t('Sort by')}>
  108. <MenuItemGroup label={<ScreenReaderContent>{I18n.t('Sort by')}</ScreenReaderContent>}>
  109. <MenuItem
  110. selected={selectedSortSetting === 'grade' && sortBySetting.direction === 'ascending'}
  111. disabled={sortBySetting.disabled}
  112. onSelect={sortBySetting.onSortByGradeAscending}
  113. >
  114. <span>{I18n.t('Grade - Low to High')}</span>
  115. </MenuItem>
  116. <MenuItem
  117. selected={selectedSortSetting === 'grade' && sortBySetting.direction === 'descending'}
  118. disabled={sortBySetting.disabled}
  119. onSelect={sortBySetting.onSortByGradeDescending}
  120. >
  121. <span>{I18n.t('Grade - High to Low')}</span>
  122. </MenuItem>
  123. </MenuItemGroup>
  124. </MenuItemFlyout>
  125. {
  126. showSeparator &&
  127. <MenuItemSeparator />
  128. }
  129. {
  130. !gradeDisplay.hidden &&
  131. <MenuItem
  132. disabled={this.props.gradeDisplay.disabled}
  133. onSelect={this.switchGradeDisplay}
  134. >
  135. <span data-menu-item-id="grade-display-switcher" style={nowrapStyle}>
  136. {displayAsPoints ? I18n.t('Display as Percentage') : I18n.t('Display as Points')}
  137. </span>
  138. </MenuItem>
  139. }
  140. {
  141. !position.isInFront &&
  142. <MenuItem onSelect={position.onMoveToFront}>
  143. <span data-menu-item-id="total-grade-move-to-front">
  144. {I18n.t('Move to Front')}
  145. </span>
  146. </MenuItem>
  147. }
  148. {
  149. !position.isInBack &&
  150. <MenuItem onSelect={position.onMoveToBack}>
  151. <span data-menu-item-id="total-grade-move-to-back">
  152. {I18n.t('Move to End')}
  153. </span>
  154. </MenuItem>
  155. }
  156. </PopoverMenu>
  157. </div>
  158. );
  159. }
  160. }
  161. export default TotalGradeColumnHeader;