Home Identifier Source Repository

src/components/student-summary.js

import React, {Component, PropTypes} from 'react'
import Immutable from 'immutable'
import cx from 'classnames'
import {oxford} from 'humanize-plus'
import plur from 'plur'
import sample from 'lodash/collection/sample'

import AvatarLetter from './avatar-letter'
import ContentEditable from './content-editable'

import studentActions from '../flux/student-actions'
import Student from '../models/student'

import countCredits from '../lib/count-credits'

import './student-summary.scss'

const goodGraduationMessage = "It looks like you'll make it! Just follow the plan, and go over my output with your advisor a few times."
const badGraduationMessage = "You haven't planned everything out yet. Ask your advisor if you need help fitting everything in."

const welcomeMessages = [
	'Hi, ',
	'Hi there, ',
	'Hello, ',
	'こんにちは、', // japanese
	'ようこそ、', // japanese
	'Fram! Fram! ',
	'Salut, ',
	'Aloha, ',
	'Привет, ',
	'Вітаю, ',
	'Sawubona, ',
	'Hei, ',
	'Hola, ', // spanish
	'Bonjour, ', // french
	'Hallo, ', // german
	'nyob zoo ', // hmong
	'你好,', // mandarin
	'안녕하세요 ', // korean
	'สวัสดี ', // thai
	'halo, ', // indonesian
]

export default class StudentSummary extends Component {
	static propTypes = {
		courses: PropTypes.instanceOf(Immutable.List),
		coursesLoaded: PropTypes.bool.isRequired,
		graduatability: PropTypes.bool.isRequired,
		student: PropTypes.instanceOf(Student).isRequired,
	}

	constructor() {
		super()
		this.state = {
			welcome: sample(welcomeMessages),
		}
	}

	render() {
		const canGraduate = this.props.graduatability
		const student = this.props.student
		const studies = student.studies

		const NameEl = (
			<ContentEditable
				className='autosize-input'
				onBlur={ev => studentActions.changeName(student.id, ev.target.value)}
				value={String(student.name)}
			/>
		)

		const degrees = studies.filter(s => s.type === 'degree')
		const majors = studies.filter(s => s.type === 'major')
		const concentrations = studies.filter(s => s.type === 'concentration')
		const emphases = studies.filter(s => s.type === 'emphasis')

		const degreeWord = plur('degree', degrees.size)
		const majorWord = plur('major', majors.size)
		const concentrationWord = plur('concentration', concentrations.size)
		const emphasisWord = plur('emphasis', 'emphases', emphases.size)

		const degreeEmphasizer = (degrees.size === 1) ? 'a ' : ''
		const majorEmphasizer = (majors.size === 1) ? 'a ' : ''
		const concentrationEmphasizer = (concentrations.size === 1) ? 'a ' : ''
		const emphasisEmphasizer = (emphases.size === 1) ? 'an ' : ''

		const degreeList = oxford(degrees.map(s => s.name).toArray())
		const majorList = oxford(majors.map(s => s.name).toArray())
		const concentrationList = oxford(concentrations.map(s => s.name).toArray())
		const emphasisList = oxford(emphases.map(s => s.name).toArray())

		const currentCredits = countCredits(this.props.courses)
		const neededCredits = student.creditsNeeded
		const enoughCredits = currentCredits >= neededCredits

		const graduationEl = (
			<ContentEditable
				className='autosize-input'
				onBlur={ev => studentActions.changeGraduation(student.id, parseInt(ev.target.value || 0))}
				value={String(student.graduation)}
			/>
		)

		const matriculationEl = (
			<ContentEditable
				className='autosize-input'
				onBlur={ev => studentActions.changeMatriculation(student.id, parseInt(ev.target.value || 0))}
				value={String(student.matriculation)}
			/>
		)

		return (
			<article className={cx('student-summary', canGraduate ? 'can-graduate' : 'cannot-graduate')}>
				<header className='student-summary--header'>
					<AvatarLetter
						className={cx(
							'student-letter',
							this.props.graduatability
								? 'can-graduate'
								: 'cannot-graduate'
						)}
						value={student.name}
					/>
					<div className='intro'>{this.state.welcome}{NameEl}!</div>
				</header>
				<div className='content'>
					<div className='paragraph'>
						After matriculating in {matriculationEl}, you are planning to graduate in {graduationEl}, with {' '}
						{(degrees.size > 0) ? `${degreeEmphasizer}${degreeList} ${degreeWord}` : `no ${degreeWord}`}
						{(majors.size || concentrations.size || emphases.size) ? (majors.size) && (concentrations.size || emphases.size) ? ', ' : ' and ' : ''}
						{(majors.size > 0) && `${majorEmphasizer}${majorWord} in ${majorList}`}
						{(majors.size && concentrations.size) ? ', and ' : ''}
						{(concentrations.size > 0) && `${concentrationEmphasizer}${concentrationWord} in ${concentrationList}`}
						{((majors.size || concentrations.size) && emphases.size) ? ', ' : ''}
						{(emphases.size > 0) && `not to mention ${emphasisEmphasizer}${emphasisWord} in ${emphasisList}`}
						{'. '}
						{this.props.coursesLoaded && `You have currently planned for ${currentCredits} of your ${neededCredits} required credits. ${enoughCredits ? '👍' : ''}`}
					</div>
					<div className='paragraph graduation-message'>
						{canGraduate ? goodGraduationMessage : badGraduationMessage}
					</div>
				</div>
			</article>
		)
	}
}