Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/actions/actionTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const FETCH_ASSESSMENT_OVERVIEWS = 'FETCH_ASSESSMENT_OVERVIEWS'
export const FETCH_GRADING = 'FETCH_GRADING'
export const FETCH_GRADING_OVERVIEWS = 'FETCH_GRADING_OVERVIEWS'
export const LOGIN = 'LOGIN'
export const SET_ROLE = 'SET_ROLE'
export const SET_TOKENS = 'SET_TOKENS'
export const SET_USERNAME = 'SET_USERNAME'
export const UPDATE_HISTORY_HELPERS = 'UPDATE_HISTORY_HELPERS'
Expand Down
7 changes: 7 additions & 0 deletions src/actions/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Grading, GradingOverview } from '../components/academy/grading/gradingS
import { IAssessment, IAssessmentOverview } from '../components/assessment/assessmentShape'
import * as actionTypes from './actionTypes'

import { Role } from '../reducers/states'

export const fetchAuth: ActionCreator<actionTypes.IAction> = (ivleToken: string) => ({
type: actionTypes.FETCH_AUTH,
payload: ivleToken
Expand Down Expand Up @@ -35,6 +37,11 @@ export const login = () => ({
type: actionTypes.LOGIN
})

export const setRole: ActionCreator<actionTypes.IAction> = (role: Role) => ({
type: actionTypes.SET_ROLE,
payload: role
})

export const setTokens: ActionCreator<actionTypes.IAction> = ({ accessToken, refreshToken }) => ({
type: actionTypes.SET_TOKENS,
payload: {
Expand Down
10 changes: 5 additions & 5 deletions src/components/Application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import Academy from '../containers/academy'
import Announcements from '../containers/AnnouncementsContainer'
import Login from '../containers/LoginContainer'
import Playground from '../containers/PlaygroundContainer'
import { sourceChapters } from '../reducers/states'
import { Role, sourceChapters } from '../reducers/states'
import NavigationBar from './NavigationBar'
import NotFound from './NotFound'

export interface IApplicationProps extends IDispatchProps, RouteComponentProps<{}> {
title: string
accessToken?: string
role?: Role
username?: string
}

Expand All @@ -29,14 +30,13 @@ const Application: React.SFC<IApplicationProps> = props => {

return (
<div className="Application">
<NavigationBar title={props.title} username={props.username} />
<NavigationBar title={props.title} username={props.username} role={props.role} />
<div className="Application__main">
<Switch>
<Route path="/academy" component={toAcademy(props)} />
<Route path="/news" component={Announcements} />
<Route path="/material" component={Announcements} />
<Route path="/playground" component={Playground} />
<Route path="/status" component={Announcements} />
<Route path="/login" render={toLogin(props)} />
<Route exact={true} path="/" render={redirectToNews} />
<Route component={NotFound} />
Expand All @@ -52,9 +52,9 @@ const Application: React.SFC<IApplicationProps> = props => {
* 2. If the user is not logged in, redirect to /login
*/
const toAcademy = (props: IApplicationProps) =>
props.accessToken === undefined
props.accessToken === undefined || props.role === undefined
? () => <Redirect to="/login" />
: () => <Academy accessToken={props.accessToken} />
: () => <Academy accessToken={props.accessToken} role={props.role!} />

const toLogin = (props: IApplicationProps) => () => (
<Login ivleToken={qs.parse(props.location.search).token} />
Expand Down
37 changes: 8 additions & 29 deletions src/components/NavigationBar.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import {
Alignment,
Icon,
Navbar,
NavbarDivider,
NavbarGroup,
NavbarHeading
} from '@blueprintjs/core'
import { Alignment, Icon, Navbar, NavbarGroup, NavbarHeading } from '@blueprintjs/core'
import { IconNames } from '@blueprintjs/icons'
import * as React from 'react'
import { NavLink } from 'react-router-dom'

import { Role } from '../reducers/states'
import Status from './academy/Status'

export interface INavigationBarProps {
title: string
username?: string
role?: Role
}

const NavigationBar: React.SFC<INavigationBarProps> = props => (
Expand Down Expand Up @@ -56,31 +53,13 @@ const NavigationBar: React.SFC<INavigationBarProps> = props => (
<div className="navbar-button-text hidden-xs">Playground</div>
</NavLink>

{props.username === undefined ? (
undefined
{props.username !== undefined && props.role !== undefined ? (
<Status username={props.username} role={props.role} />
) : (
<>
<div className="visible-xs">
<NavbarDivider className="thin-divider" />
</div>
<div className="hidden-xs">
<NavbarDivider className="default-divider" />
</div>
<NavLink
to="/status"
activeClassName="pt-active"
className="NavigationBar__link pt-button pt-minimal"
>
<Icon icon={IconNames.USER} />
<div className="navbar-button-text hidden-xs">{titleCase(props.username)}</div>
</NavLink>
</>
undefined
)}
</NavbarGroup>
</Navbar>
)

const titleCase = (str: string) =>
str.replace(/\w\S*/g, wrd => wrd.charAt(0).toUpperCase() + wrd.substr(1).toLowerCase())

export default NavigationBar
3 changes: 1 addition & 2 deletions src/components/__tests__/__snapshots__/Application.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

exports[`Application renders correctly 1`] = `
"<div className=\\"Application\\">
<NavigationBar title=\\"Cadet\\" username={[undefined]} />
<NavigationBar title=\\"Cadet\\" username={[undefined]} role={[undefined]} />
<div className=\\"Application__main\\">
<Switch>
<Route path=\\"/academy\\" component={[Function]} />
<Route path=\\"/news\\" component={[Function: Connect]} />
<Route path=\\"/material\\" component={[Function: Connect]} />
<Route path=\\"/playground\\" component={[Function: C]} />
<Route path=\\"/status\\" component={[Function: Connect]} />
<Route path=\\"/login\\" render={[Function]} />
<Route exact={true} path=\\"/\\" render={[Function: redirectToNews]} />
<Route component={[Function: NotFound]} />
Expand Down
14 changes: 0 additions & 14 deletions src/components/__tests__/__snapshots__/NavigationBar.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,6 @@ exports[`NavigationBar renders correctly with username 1`] = `
Playground
</div>
</NavLink>
<Symbol(react.fragment)>
<div className=\\"visible-xs\\">
<Blueprint2.NavbarDivider className=\\"thin-divider\\" />
</div>
<div className=\\"hidden-xs\\">
<Blueprint2.NavbarDivider className=\\"default-divider\\" />
</div>
<NavLink to=\\"/status\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"user\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Evis Rucer
</div>
</NavLink>
</Symbol(react.fragment)>
</Blueprint2.NavbarGroup>
</Blueprint2.Navbar>"
`;
31 changes: 20 additions & 11 deletions src/components/academy/NavigationBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@ import { IconNames } from '@blueprintjs/icons'
import * as React from 'react'
import { NavLink } from 'react-router-dom'

import { Role } from '../../reducers/states'
import { assessmentCategoryLink } from '../../utils/paramParseHelpers'
import { AssessmentCategories } from '../assessment/assessmentShape'

const NavigationBar: React.SFC<{}> = () => (
type NavigationBarProps = OwnProps

type OwnProps = {
role: Role
}

const NavigationBar: React.SFC<NavigationBarProps> = props => (
<Navbar className="NavigationBar secondary-navbar">
<NavbarGroup align={Alignment.LEFT}>
<NavLink
Expand Down Expand Up @@ -45,16 +52,18 @@ const NavigationBar: React.SFC<{}> = () => (
<div className="navbar-button-text hidden-xs">Contests</div>
</NavLink>
</NavbarGroup>
<NavbarGroup align={Alignment.RIGHT}>
<NavLink
to={`/academy/grading`}
activeClassName="pt-active"
className="NavigationBar__link pt-button pt-minimal"
>
<Icon icon={IconNames.ENDORSED} />
<div className="navbar-button-text hidden-xs">Grading</div>
</NavLink>
</NavbarGroup>
{props.role === Role.Admin || props.role === Role.Staff ? (
<NavbarGroup align={Alignment.RIGHT}>
<NavLink
to={'/academy/grading'}
activeClassName="pt-active"
className="NavigationBar__link pt-button pt-minimal"
>
<Icon icon={IconNames.ENDORSED} />
<div className="navbar-button-text hidden-xs">Grading</div>
</NavLink>
</NavbarGroup>
) : null}
</Navbar>
)

Expand Down
37 changes: 37 additions & 0 deletions src/components/academy/Status.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { NavbarDivider, Popover, Text } from '@blueprintjs/core'
import { IconNames } from '@blueprintjs/icons'
import * as React from 'react'

import { Role } from '../../reducers/states'
import { controlButton } from '../commons'

type StatusProps = OwnProps

type OwnProps = {
username: string
role: Role
}

const Status: React.SFC<StatusProps> = props => (
<>
<div className="visible-xs">
<NavbarDivider className="thin-divider" />
</div>
<div className="hidden-xs">
<NavbarDivider className="default-divider" />
</div>
<Popover popoverClassName="Popover-share pt-dark" inheritDarkTheme={true}>
<div className="navbar-button-text hidden-xs">
{controlButton(titleCase(props.username), IconNames.USER)}
</div>
<Text>
<h4>{`Source Academy, ${titleCase(props.role)}`}</h4>
</Text>
</Popover>
</>
)

const titleCase = (str: string) =>
str.replace(/\w\S*/g, wrd => wrd.charAt(0).toUpperCase() + wrd.substr(1).toLowerCase())

export default Status
32 changes: 32 additions & 0 deletions src/components/academy/__tests__/NavigationBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { shallow } from 'enzyme'
import * as React from 'react'

import { Role } from '../../../reducers/states'
import NavigationBar from '../NavigationBar'

test('Grading NavLink does NOT renders for Role.Student', () => {
const props = { role: Role.Student }
const tree = shallow(<NavigationBar {...props} />)
expect(tree.debug()).toMatchSnapshot()
expect(
tree.filterWhere(shallowTree => shallowTree.find({ to: 'academy/grading' }).exists())
).toHaveLength(0)
})

test('Grading NavLink renders for Role.Staff', () => {
const props = { role: Role.Staff }
const tree = shallow(<NavigationBar {...props} />)
expect(tree.debug()).toMatchSnapshot()
expect(
tree.filterWhere(shallowTree => shallowTree.find({ to: '/academy/grading' }).exists())
).toHaveLength(1)
})

test('Grading NavLink renders for Role.Admin', () => {
const props = { role: Role.Admin }
const tree = shallow(<NavigationBar {...props} />)
expect(tree.debug()).toMatchSnapshot()
expect(
tree.filterWhere(shallowTree => shallowTree.find({ to: '/academy/grading' }).exists())
).toHaveLength(1)
})
110 changes: 110 additions & 0 deletions src/components/academy/__tests__/__snapshots__/NavigationBar.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Grading NavLink does NOT renders for Role.Student 1`] = `
"<Blueprint2.Navbar className=\\"NavigationBar secondary-navbar\\">
<Blueprint2.NavbarGroup align=\\"left\\">
<NavLink to=\\"/academy/missions\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"flame\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Missions
</div>
</NavLink>
<NavLink to=\\"/academy/sidequests\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"lightbulb\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Sidequests
</div>
</NavLink>
<NavLink to=\\"/academy/paths\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"predictive-analysis\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Paths
</div>
</NavLink>
<NavLink to=\\"/academy/contests\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"comparison\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Contests
</div>
</NavLink>
</Blueprint2.NavbarGroup>
</Blueprint2.Navbar>"
`;

exports[`Grading NavLink renders for Role.Admin 1`] = `
"<Blueprint2.Navbar className=\\"NavigationBar secondary-navbar\\">
<Blueprint2.NavbarGroup align=\\"left\\">
<NavLink to=\\"/academy/missions\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"flame\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Missions
</div>
</NavLink>
<NavLink to=\\"/academy/sidequests\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"lightbulb\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Sidequests
</div>
</NavLink>
<NavLink to=\\"/academy/paths\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"predictive-analysis\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Paths
</div>
</NavLink>
<NavLink to=\\"/academy/contests\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"comparison\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Contests
</div>
</NavLink>
</Blueprint2.NavbarGroup>
<Blueprint2.NavbarGroup align=\\"right\\">
<NavLink to=\\"/academy/grading\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"endorsed\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Grading
</div>
</NavLink>
</Blueprint2.NavbarGroup>
</Blueprint2.Navbar>"
`;

exports[`Grading NavLink renders for Role.Staff 1`] = `
"<Blueprint2.Navbar className=\\"NavigationBar secondary-navbar\\">
<Blueprint2.NavbarGroup align=\\"left\\">
<NavLink to=\\"/academy/missions\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"flame\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Missions
</div>
</NavLink>
<NavLink to=\\"/academy/sidequests\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"lightbulb\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Sidequests
</div>
</NavLink>
<NavLink to=\\"/academy/paths\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"predictive-analysis\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Paths
</div>
</NavLink>
<NavLink to=\\"/academy/contests\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"comparison\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Contests
</div>
</NavLink>
</Blueprint2.NavbarGroup>
<Blueprint2.NavbarGroup align=\\"right\\">
<NavLink to=\\"/academy/grading\\" activeClassName=\\"pt-active\\" className=\\"NavigationBar__link pt-button pt-minimal\\" ariaCurrent=\\"true\\">
<Blueprint2.Icon icon=\\"endorsed\\" />
<div className=\\"navbar-button-text hidden-xs\\">
Grading
</div>
</NavLink>
</Blueprint2.NavbarGroup>
</Blueprint2.Navbar>"
`;
Loading