Skip to content

Commit 22bb557

Browse files
committed
Merge pull request #74 from openstax/custom-notices
Add methods to display notices manually
2 parents fe71483 + 8d0407c commit 22bb557

File tree

7 files changed

+81
-6
lines changed

7 files changed

+81
-6
lines changed

resources/styles/demo.less

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@
88
margin: 100px 0;
99

1010
}
11+
.notices {
12+
.test-message {
13+
display: flex;
14+
align-items: center;
15+
justify-content: space-between;
16+
width: 500px;
17+
}
18+
}
1119

1220
.exercisePreview-demo, .exercise-demo, .multipartExercise-demo {
1321
max-width: 800px;

src/components/demo.cjsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,26 @@ NoticesDemo = React.createClass
312312
)
313313
Notifications.startPolling()
314314

315+
showMessage: ->
316+
Notifications.display(
317+
message: @refs.message.getDOMNode().value,
318+
level: @refs.type.getDOMNode().value
319+
)
320+
315321
render: ->
316322
<div className="notices">
317323
<NotificationBar />
324+
<div className="test-message">
325+
<span>Test Message:</span>
326+
<input type="text" ref="message" />
327+
<select ref="type">
328+
<option value="success">Success</option>
329+
<option value="notice" selected>Notice</option>
330+
<option value="alert">Alert</option>
331+
<option value="error">Error</option>
332+
</select>
333+
<button onClick={@showMessage}>Display</button>
334+
</div>
318335
<button onClick={@startPoll}>Start Polling</button>
319336
</div>
320337

src/components/notifications/bar.cjsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ _ = require 'underscore'
44
Notifications = require '../../model/notifications'
55

66
TYPES =
7-
tutor: require './system'
7+
system: require './system'
88
accounts: require './email'
99

1010
NotificationBar = React.createClass
@@ -23,7 +23,7 @@ NotificationBar = React.createClass
2323

2424
<div className="openstax-notifications-bar">
2525
{for notice in notifications
26-
Component = TYPES[notice.type]
26+
Component = TYPES[notice.type] or TYPES['system']
2727
<Component key={notice.id} notice={notice} />}
2828
</div>
2929

src/components/notifications/system.cjsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
React = require 'react'
2+
classnames = require 'classnames'
23

34
Notifications = require '../../model/notifications'
45

@@ -13,10 +14,19 @@ SystemNotification = React.createClass
1314
Notifications.acknowledge(@props.notice)
1415
undefined # silence React warning about return value
1516

17+
getIcon: ->
18+
return @props.notice.icon if @props.notice.icon
19+
switch @props.notice.level
20+
when 'alert' then 'exclamation-triangle'
21+
when 'error', 'warning' then 'exclamation-circle'
22+
else
23+
'info-circle'
24+
1625
render: ->
17-
<div className="notification system">
26+
27+
<div className={classnames('notification', 'system', @props.notice.level)}>
1828
<span className="body">
19-
<i className='icon fa fa-info-circle' />
29+
<i className={"icon fa fa-#{@getIcon()}"} />
2030
{@props.notice.message}
2131
</span>
2232
<a className='dismiss' onClick={@acknowledge}>Dismiss</a>

src/model/notifications.coffee

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@ URLs = require './urls'
55
EVENT_BUS = new EventEmitter2
66
POLLERS = {}
77

8+
NOTICES = []
9+
10+
CLIENT_ID = 'client-specified'
811
Poller = require './notifications/pollers'
912

1013
Notifications = {
1114

15+
display: (notice) ->
16+
# fill in an id and type if not provided
17+
NOTICES.push( _.defaults(_.clone(notice), id: _.uniqueId(CLIENT_ID), type: CLIENT_ID ))
18+
@emit('change')
19+
1220
_startPolling: (type, url) ->
1321
POLLERS[type] ||= Poller.forType(@, type)
1422
POLLERS[type].setUrl(url)
@@ -24,10 +32,14 @@ Notifications = {
2432

2533

2634
acknowledge: (notice) ->
27-
POLLERS[notice.type].acknowledge(notice)
35+
if notice.type is CLIENT_ID
36+
NOTICES = _.without(NOTICES, _.findWhere(NOTICES, id: notice.id))
37+
@emit('change')
38+
else
39+
POLLERS[notice.type].acknowledge(notice)
2840

2941
getActive: ->
30-
notices = []
42+
notices = _.clone NOTICES
3143
for type, poller of POLLERS
3244
notices = notices.concat( poller.getActiveNotifications() )
3345
notices

test/components/notifications/system.spec.coffee

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,13 @@ describe 'System Notifications', ->
2020
Testing.renderComponent( SystemNotifications, props: @props ).then ({dom}) =>
2121
Testing.actions.click(dom.querySelector('.dismiss'))
2222
expect(Notifications.acknowledge).to.have.been.calledWith(@props.notice)
23+
24+
it 'displays icon based on level', ->
25+
@props.notice.level = 'alert'
26+
Testing.renderComponent( SystemNotifications, props: @props ).then ({dom}) ->
27+
expect(dom.querySelector('.fa-exclamation-triangle')).to.exist
28+
29+
it 'displays icon provided', ->
30+
@props.notice.icon = 'beer'
31+
Testing.renderComponent( SystemNotifications, props: @props ).then ({dom}) ->
32+
expect(dom.querySelector('.fa-beer')).to.exist

test/model/notifications.spec.coffee

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,21 @@ describe 'Notifications', ->
2525
URLs.update(tutor_notices_url: 'http://localhost:3001/api/notifications')
2626
Notifications.startPolling(@windowImpl)
2727
expect(Poller::poll).to.have.callCount(2)
28+
29+
30+
it 'can display and confirm manual notifications', ->
31+
changeListener = sinon.stub()
32+
notice = {message: 'hello world', icon: 'globe'}
33+
Notifications.on('change', changeListener)
34+
Notifications.display(notice)
35+
expect(changeListener).to.have.been.called
36+
37+
active = Notifications.getActive()
38+
expect(active).to.have.length(1)
39+
# should have copied the object vs mutating it
40+
expect(active[0]).not.to.not.equal(notice)
41+
expect(active[0].type).to.exist
42+
43+
Notifications.acknowledge(active[0])
44+
expect(changeListener).to.have.callCount(2)
45+
expect(Notifications.getActive()).to.be.empty

0 commit comments

Comments
 (0)