renderQuickLinks (user, course) { return (user.short_name && ( course.permissions.manage_grades || course.permissions.view_all_grades || course.permissions.view_analytics )) ? ( <section className="StudentContextTray__Section StudentContextTray-QuickLinks" > {StudentContextTray.renderQuickLink( I18n.t('Grades'), I18n.t('View grades for %{name}', { name: user.short_name }), `/courses/${this.props.courseId}/grades/${this.props.studentId}`, () => course.permissions.manage_grades || course.permissions.view_all_grades )} {StudentContextTray.renderQuickLink( I18n.t('Analytics'), I18n.t('View analytics for %{name}', { name: user.short_name }), `/courses/${this.props.courseId}/analytics/users/${this.props.studentId}`, () => course.permissions.view_analytics && user.analytics )} </section> ) : null }
render () { const {user, courseId, canMasquerade} = this.props if (Object.keys(user).includes('avatar_url')) { const name = user.short_name || user.name || 'user'; return ( <div className="StudentContextTray__Avatar"> <Link href={`/courses/${this.props.courseId}/users/${user._id}`} aria-label={I18n.t('Go to %{name}\'s profile', {name})}> <InstUIAvatar size="x-large" name={name} src={user.avatar_url} /> </Link> { canMasquerade && ( <Typography size="x-small" weight="bold" as="div"> <a href={`/courses/${courseId}?become_user_id=${user._id}`} aria-label={I18n.t('Act as %{name}', { name: user.short_name })} > {I18n.t('Act as User')} </a> </Typography> ) } </div> ) } return null }
formatValueText (currentRating, maxRating) { const valueText = {} valueText[I18n.t('High')] = currentRating === maxRating valueText[I18n.t('Moderate')] = currentRating === 2 valueText[I18n.t('Low')] = currentRating === 1 valueText[I18n.t('None')] = currentRating === 0 return classnames(valueText) }
{submissions.map((submission) => { return ( <div key={submission.id} className="StudentContextTray-Progress__Bar"> <Tooltip tip={submission.assignment.name} as={Link} href={`${submission.assignment.html_url}/submissions/${submission.user_id}`} placement="top" > <Progress size="small" successColor={false} label={I18n.t('Grade')} valueMax={submission.assignment.points_possible} valueNow={submission.score || 0} formatValueText={() => SubmissionProgressBars.displayScreenreaderGrade(submission)} formatDisplayedValue={() => ( <Typography size="x-small" color="secondary"> {SubmissionProgressBars.displayGrade(submission)} </Typography> )} /> </Tooltip> </div> ) })}
render () { if ( typeof this.props.user.enrollments !== 'undefined' && Object.keys(this.props.analytics).length > 0 ) { return ( <section className="StudentContextTray__Section StudentContextTray-MetricsList"> <InstUIMetricsList> <MetricsListItem label={I18n.t('Grade')} value={this.grade} /> <MetricsListItem label={I18n.t('Missing')} value={this.missingCount} /> <MetricsListItem label={I18n.t('Late')} value={this.lateCount} /> </InstUIMetricsList> </section> ) } else { return null } }
render () { const lastActivity = this.lastActivity if (lastActivity) { return ( <span>{I18n.t('Last login:')} <FriendlyDatetime dateTime={lastActivity} /></span> ) } else { return null } }
render () { const sections = this.sections if (sections.length > 0) { const sectionNames = sections.map((section) => { return section.name }).sort() return ( <span>{I18n.t("Section: %{section_names}", { section_names: sectionNames.join(', ') })}</span> ) } else { return null } }
static renderIcon (grade) { const iconClass = classnames({ 'icon-check': grade === 'complete', 'icon-x': grade === 'incomplete' }) return ( <div> <span className='screenreader-only'> {I18n.t("%{grade}", {grade: grade})} </span> <i className={iconClass}></i> </div> ) }
static displayScreenreaderGrade (submission) { const {score, grade, excused} = submission const pointsPossible = submission.assignment.points_possible let display if (excused) { display = I18n.t('excused') } else if (grade.match(/%/) || grade.match(/complete/)) { // Grade is a percentage or in/complete, just show it display = grade } else { // Default to show score out of points possible display = `${score}/${pointsPossible}` } return display }
render () { const {submissions} = this.props if (submissions.length > 0) { return ( <section className="StudentContextTray__Section StudentContextTray-Progress"> <Heading level="h4" as="h3" border="bottom"> {I18n.t("Last %{length} Graded Items", {length: submissions.length})} </Heading> {submissions.map((submission) => { return ( <div key={submission.id} className="StudentContextTray-Progress__Bar"> <Tooltip tip={submission.assignment.name} as={Link} href={`${submission.assignment.html_url}/submissions/${submission.user_id}`} placement="top" > <Progress size="small" successColor={false} label={I18n.t('Grade')} valueMax={submission.assignment.points_possible} valueNow={submission.score || 0} formatValueText={() => SubmissionProgressBars.displayScreenreaderGrade(submission)} formatDisplayedValue={() => ( <Typography size="x-small" color="secondary"> {SubmissionProgressBars.displayGrade(submission)} </Typography> )} /> </Tooltip> </div> ) })} </section> ) } else { return null } }
render () { const { data: { loading, course, user } } = this.props return ( <div> {this.state.messageFormOpen ? ( <MessageStudents contextCode={`course_${course._id}`} onRequestClose={this.handleMessageFormClose} open={this.state.messageFormOpen} recipients={[{ id: user._id, displayName: user.short_name }]} title='Send a message' /> ) : null} <Tray label={I18n.t('Student Details')} closeButtonLabel={I18n.t('Close')} closeButtonRef={this.getCloseButtonRef} applicationElement={() => document.getElementById('application')} open={this.state.isOpen} onDismiss={this.handleRequestClose} placement='end' zIndex='1000' > <aside className={user && user.avatar_url ? 'StudentContextTray StudentContextTray--withAvatar' : 'StudentContextTray' } > {loading ? ( <div className='StudentContextTray__Spinner'> <Spinner title={I18n.t('Loading')} size='large' /> </div> ) : ( <div> <header className="StudentContextTray-Header"> <Avatar user={user} canMasquerade={course.permissions.become_user} courseId={this.props.courseId} /> <div className="StudentContextTray-Header__Layout"> <div className="StudentContextTray-Header__Content"> {user.short_name ? ( <div className="StudentContextTray-Header__Name"> <Heading level="h3" as="h2"> <span className="StudentContextTray-Header__NameLink"> <Link href={`/courses/${this.props.courseId}/users/${this.props.studentId}`} aria-label={I18n.t('Go to %{name}\'s profile', {name: user.short_name})} > {user.short_name} </Link> </span> </Heading> </div> ) : null} <div className="StudentContextTray-Header__CourseName"> <Text size="medium" as="div" lineHeight="condensed"> {course.name} </Text> </div> <Text size="x-small" color="secondary" as="div"> <SectionInfo user={user} /> </Text> <Text size="x-small" color="secondary" as="div"> <LastActivity user={user} /> </Text> </div> {course.permissions.send_messages ? ( <div className="StudentContextTray-Header__Actions"> <Button ref={ (b) => this.messageStudentsButton = b } variant="icon" size="small" onClick={this.handleMessageButtonClick} > <ScreenReaderContent> {I18n.t('Send a message to %{student}', {student: user.short_name})} </ScreenReaderContent> {/* Note: replace with instructure-icon */} <i className="icon-email" aria-hidden="true" /> </Button> </div> ) : null } </div> </header> {this.renderQuickLinks(user, course)} <MetricsList user={user} analytics={user.analytics} /> <SubmissionProgressBars submissions={course.submissionsConnection.edges.map(n => n.submission)} /> {user.analytics ? ( <section className="StudentContextTray__Section StudentContextTray-Ratings"> <Heading level="h4" as="h3" border="bottom"> {I18n.t("Activity Compared to Class")} </Heading> <div className="StudentContextTray-Ratings__Layout"> <Rating metric={user.analytics.participations} label={I18n.t('Participation')} /> <Rating metric={user.analytics.page_views} label={I18n.t('Page Views')} /> </div> </section> ) : null} </div> )} </aside> </Tray> </div> ); }