Skip to content

Commit

Permalink
Various Fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
JaciBrunning committed Jul 21, 2019
1 parent 528c255 commit 2845dcc
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 36 deletions.
95 changes: 73 additions & 22 deletions app/javascript/components/Planner.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import _ from 'lodash';
import update from 'immutability-helper';
import Unit from './planner/Unit';
import MultiUnit from './planner/MultiUnit';
import uuidv1 from 'uuid/v1';
import { DragDropContext } from 'react-beautiful-dnd';
import { EasyDraggable } from './DnD';
import { UnitCollection } from './planner/UnitCollection';
import { mapObject } from '../utils/CollectionUtils';
import { calcPrereqs } from '../utils/PlannerUtils';
import { calcPrereqs, estimateAvailability } from '../utils/PlannerUtils';

const UnitDraggable = (props) => (
<EasyDraggable
Expand All @@ -33,7 +34,7 @@ const UnitDraggable = (props) => (
const Period = (props) => (
<UnitCollection
editableTitle
className="period"
className={ "period " + props.class }
{...props} />
)

Expand All @@ -47,20 +48,17 @@ const Arena = (props) => (
class Planner extends React.Component {
constructor(props) {
super(props)
this.periodId = 0

let urlParams = new URLSearchParams(window.location.search)
this.allUnits = _.keyBy(Object.values(this.props.units).map(u => u.unit), 'code')
let part = _.partition(this.props.units, u => u.optional)
let [optionals, non_optionals] = part;
this.optionalChoices = _.groupBy(optionals, 'planned_period')

if (urlParams.has('load')) {
// TODO: Validate state
this.state = JSON.parse(atob(urlParams.get('load')))
} else {
let part = _.partition(this.props.units, u => u.optional)
let [optionals, non_optionals] = part;

this.optionalChoices = _.groupBy(optionals, 'planned_period')

let periodMap = mapObject(_.groupBy(non_optionals, 'planned_period'), (k, v) => {
return {
id: k,
Expand All @@ -73,6 +71,7 @@ class Planner extends React.Component {
orientation: 'horizontal', orientationComplement: 'vertical',
collections: Object.keys(periodMap).sort(),
highlights: {},
highlightAvail: [],
prereqs: {},
arena: {
id: 'arena',
Expand Down Expand Up @@ -105,6 +104,10 @@ class Planner extends React.Component {
return found
}

canChooseUnit = code => {
return this.findAllUnitsByCode(code).length == 0
}

splitOptional = (period, index, selected) => {
let optU = this.state[period].units[index]
let optUnit = this.getUnit(optU.code)
Expand Down Expand Up @@ -156,12 +159,8 @@ class Planner extends React.Component {
chosen: {
$splice: [[parentRef.chosenIdx, 1]]
},
hidden: {
$set: false
},
credits: {
$set: parentU.credits + usUnit.credits
}
hidden: { $set: false },
credits: { $set: parentU.credits + usUnit.credits }
}
}
}
Expand All @@ -174,9 +173,8 @@ class Planner extends React.Component {
$splice: [[index, 1]]
}
},
highlights: {
$set: {}
}
highlights: { $set: {} },
highlightAvail: { $set: [] }
})

this.updateWithPrereqs(nextState)
Expand Down Expand Up @@ -266,7 +264,10 @@ class Planner extends React.Component {
}

onDragStart = result => {
this.setState({ highlights: this.assignPrereqs(result.draggableId) })
this.setState({
highlights: this.assignPrereqs(result.draggableId),
highlightAvail: this.allUnits[result.draggableId].unit_availabilities
})
}

onDragEnd = result => {
Expand All @@ -278,6 +279,8 @@ class Planner extends React.Component {
if (this.state[srcPeriod].units[srcIdx].optRef) {
// Optional dragged outside - remove it
this.removeOptional(srcPeriod, srcIdx)
} else {
this.setState({ highlights: {}, highlightAvail: {} })
}
return;
}
Expand All @@ -296,7 +299,8 @@ class Planner extends React.Component {
...this.state[srcPeriod],
units: srcUnitCopy
},
highlights: {}
highlights: {},
highlightAvail: []
}

this.updateWithPrereqs(nextState)
Expand All @@ -316,7 +320,8 @@ class Planner extends React.Component {
...this.state[dstPeriod],
units: dstUnitCopy
},
highlights: {}
highlights: {},
highlightAvail: []
}

this.updateWithPrereqs(nextState)
Expand All @@ -338,6 +343,7 @@ class Planner extends React.Component {
unit={unit}
getUnit={this.getUnit}
getOptionalChoices={this.getOptionalChoices}
canChooseUnit={this.canChooseUnit}
splitOptional={(selected) => this.splitOptional(container.id, index, selected)}
highlight={this.state.highlights[unit.code]}
prereqStatus={this.state.prereqs[unit.code]}
Expand All @@ -347,6 +353,42 @@ class Planner extends React.Component {
})
)

addPeriod = () => {
const id = `period-${uuidv1()}`
const nextState = update(this.state, {
[id]: {
$set: {
id: id,
title: "Set Title...",
canRemove: true,
units: []
}
},
collections: {
$push: [ id ]
}
})

this.setState(nextState)
}

removePeriod = (period) => {
const nextState = update(this.state, {
arena: {
units: {
$push: this.state[period].units
},
},
collections: {
$splice: [[ this.state.collections.indexOf(period), 1 ]]
},
[period]: {
$set: undefined
}
})
this.setState(nextState)
}

render() {
return (
<DragDropContext onDragStart={this.onDragStart} onDragEnd={this.onDragEnd}>
Expand All @@ -355,6 +397,9 @@ class Planner extends React.Component {
<i className="fas fa-sync">&nbsp;</i>
Flip Orientation
</button>
<button className="btn btn-success" onClick={this.addPeriod}>
<i className="fas fa-plus"></i>
</button>
<input type="text" className="form-control save-load" value={this.getStateURL()} disabled />
</div>

Expand All @@ -369,11 +414,17 @@ class Planner extends React.Component {
let v = this.state[k]

return (
<Period key={k} id={k}
<Period
key={k} id={k}
direction={this.state.orientation}
title={v.title}
canRemove={v.canRemove}
onRemove={this.removePeriod}
class={
estimateAvailability(v.title, this.state.highlightAvail) ?
"period-avail-match" : ""
}
onTitleChange={d => this.changeTitle(k, d.title)}>

{ this.unitsFor(v) }
</Period>
)
Expand Down
9 changes: 6 additions & 3 deletions app/javascript/components/planner.scss
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ $selected-unit-color: #eeffee;
font-weight: bold;
}

&.period-avail-match {
background-color: #bbffff;
}

&.draggedOver {
background-color: $selected-container-color;
}
Expand Down Expand Up @@ -146,8 +150,7 @@ $selected-unit-color: #eeffee;
background-color: #fbb;
}

&.avail-bad:not(.completed) {
background-color: #622 !important;
color: #eee;
&.avail-bad {
box-shadow: 0 0 1em #622;
}
}
28 changes: 19 additions & 9 deletions app/javascript/components/planner/MultiUnit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,30 @@ class MultiUnit extends AbstractUnit {
'credits' in this.props ? this.props.credits : this.props.unit.credits
)

canChooseUnit = (code) => {
if (!this.props.canChooseUnit(code)) return false
if (this.props.chosen && _.includes(this.props.chosen, code)) return false;
return true;
}

render() {
return (
<div className="unit-item">
{
this.props.unit.freeform === 'optional' ?
<DropdownButton id={this.props.unit.code + "-dd"} title="Select Opts" style={{position: 'unset'}}>
{
(this.props.getOptionalChoices(this.props.unit.code) || []).map(u => (
(this.props.chosen && _.includes(this.props.chosen, u.code)) ? [] :
<Dropdown.Item key={u.code} onSelect={() => this.props.splitOptional(u)}>{ u.code } - { u.name }</Dropdown.Item>
))
}
</DropdownButton>
: []
<DropdownButton id={this.props.unit.code + "-dd"} title="Select Opts" style={{position: 'unset'}}>
{
(this.props.getOptionalChoices(this.props.unit.code) || []).map(u => (
(!this.canChooseUnit(u.code)) ? [] :
<Dropdown.Item key={u.code} onSelect={() => this.props.splitOptional(u)}>{ u.code } - { u.name }</Dropdown.Item>
))
}
</DropdownButton>
:
<span>
<p className="unit-title"> Elective Unit(s) </p>
<p className="unit-subtitle"> Support coming soon </p>
</span>
}
{ !this.available() ? this.availabilityTooltip() : [] }
{ this.footer(false) }
Expand Down
4 changes: 4 additions & 0 deletions app/javascript/components/planner/UnitCollection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ export const UnitCollection = (props) => (
{...props}
pre={
<React.Fragment>
{
!props.canRemove ? [] :
<a onClick={e => props.onRemove(props.id)}><i className="fas fa-times">&nbsp;</i></a>
}
<MaybeEditableTitle
editable={props.editableTitle}
title={props.title}
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/utils/PlannerUtils.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function calcPrereqs(code, out, internalUnits, levelOf, isCompleted) {

let operands = []
let opA = tryResolveToOperand(code, a, out, internalUnits, levelOf, isCompleted)
let opB = tryResolveToOperand(code, a, out, internalUnits, levelOf, isCompleted)
let opB = tryResolveToOperand(code, b, out, internalUnits, levelOf, isCompleted)

if (opA) operands.push(opA)
if (opB) operands.push(opB)
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"react-graph-vis": "^1.0.2",
"react-motion": "^0.5.2",
"react_ujs": "^2.5.0",
"truncate": "^2.1.0"
"truncate": "^2.1.0",
"uuid": "^3.3.2"
},
"devDependencies": {
"webpack-dev-server": "^3.7.2"
Expand Down

0 comments on commit 2845dcc

Please sign in to comment.