Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Enes Tasbasi
whats-open-web
Commits
c6eb5df3
Commit
c6eb5df3
authored
Jan 23, 2018
by
Andrew Hrdy
Browse files
Started alerts with bell icon design.
parent
0f8bb75e
Changes
11
Hide whitespace changes
Inline
Side-by-side
.eslintrc.json
View file @
c6eb5df3
...
...
@@ -117,6 +117,7 @@
"template-curly-spacing"
:
"error"
,
"react/no-unescaped-entities"
:
"off"
,
"react/prop-types"
:
"off"
,
"react/no-find-dom-node"
:
"off"
,
"react/boolean-prop-naming"
:
"warn"
,
"react/no-danger"
:
"error"
,
"react/no-typos"
:
"warn"
,
...
...
src/components/Alert.js
0 → 100644
View file @
c6eb5df3
import
React
from
'
react
'
;
import
classNames
from
'
classnames
'
;
import
{
findLink
}
from
'
../utils/nameUtils
'
;
const
Alert
=
({
alert
})
=>
{
const
getUrgencyClass
=
()
=>
{
switch
(
alert
.
urgency_tag
)
{
case
'
emergency
'
:
return
'
alert-emergency
'
;
case
'
major
'
:
return
'
alert-major
'
;
case
'
minor
'
:
return
'
alert-minor
'
;
case
'
info
'
:
default
:
return
'
alert-info
'
;
}
};
const
getMessage
=
()
=>
{
const
links
=
findLink
(
alert
.
message
);
if
(
!
links
)
{
return
alert
.
message
;
}
return
(
<
span
>
{
alert
.
message
.
substring
(
0
,
links
.
index
)}
<
a
href
=
{
links
[
0
]}
className
=
{
'
alert-link
'
}
target
=
"
_blank
"
rel
=
"
noopener
"
>
{
links
[
0
]}
<
/a
>
{
alert
.
message
.
substring
(
links
.
index
+
links
[
0
].
length
)}
<
/span
>
);
};
return
(
<
div
className
=
{
classNames
(
'
alert
'
,
getUrgencyClass
())}
>
{
getMessage
()}
<
/div
>
);
};
export
default
Alert
;
\ No newline at end of file
src/components/AlertContainer.js
deleted
100644 → 0
View file @
0f8bb75e
import
React
from
'
react
'
;
import
NotificationSystem
from
'
react-notification-system
'
;
class
AlertContainer
extends
React
.
Component
{
notificationSystem
;
constructor
()
{
super
();
/*
The alerts that have been shown need to be stored because componentWillReceiveProps will be called on
change detection. Because of this, whenever an action occurs on the screen, the alerts will be reshown.
*/
this
.
state
=
{
shownAlertIds
:
[]
};
}
componentWillReceiveProps
(
nextProps
)
{
//TODO: Only show alerts that the user has not seen before.
nextProps
.
alerts
.
filter
((
alert
)
=>
!
this
.
state
.
shownAlertIds
.
includes
(
alert
.
id
)).
filter
(
this
.
isAlertActive
).
forEach
((
alert
)
=>
{
this
.
addNotification
(
alert
);
});
}
isAlertActive
=
(
alert
)
=>
{
const
curDate
=
new
Date
();
const
startDate
=
new
Date
(
alert
.
start_datetime
);
const
endDate
=
new
Date
(
alert
.
end_datetime
);
return
curDate
>
startDate
&&
curDate
<
endDate
;
};
addNotification
=
(
alert
)
=>
{
//TODO: Support alerts with links
this
.
state
.
shownAlertIds
.
push
(
alert
.
id
);
this
.
notificationSystem
.
addNotification
({
message
:
alert
.
message
,
level
:
this
.
resolveNotificationLevel
(
alert
),
position
:
'
bl
'
,
autoDismiss
:
6
,
dismissible
:
true
,
uid
:
alert
.
id
});
};
/**
* The What's Open API tells us if an alert is an info, minor, major, or emergency. However, the library that
* deals with notifications requires either a info, success, warning, or error. This function maps the
* What's Open API to the library.
*
* @param alert The What's Open Alert.
* @returns {string} The notification level used by the third party library.
*/
resolveNotificationLevel
=
(
alert
)
=>
{
switch
(
alert
.
urgency_tag
)
{
case
'
emergency
'
:
return
'
error
'
;
case
'
major
'
:
return
'
warning
'
;
case
'
minor
'
:
return
'
success
'
;
default
:
case
'
info
'
:
return
'
info
'
;
}
};
render
()
{
return
(
<
div
>
<
NotificationSystem
ref
=
{(
c
)
=>
{
this
.
notificationSystem
=
c
;
}}
/
>
<
/div
>
);
}
}
export
default
AlertContainer
;
\ No newline at end of file
src/components/AppBar.js
View file @
c6eb5df3
...
...
@@ -7,6 +7,7 @@ import IconButton from 'material-ui/IconButton';
import
MenuIcon
from
'
material-ui-icons/Menu
'
;
import
SearchBar
from
'
../containers/SearchBar
'
;
import
classNames
from
'
classnames
'
;
import
AlertContainer
from
'
../containers/AlertContainer
'
;
class
CustomAppBar
extends
React
.
Component
{
...
...
@@ -38,6 +39,7 @@ class CustomAppBar extends React.Component {
What
'
s Open
</Typography>
</div>
<AlertContainer/>
<div className={
'
app
-
bar
-
search
-
menu
'
}>
<SearchBar onSearchExpand={() => this.setState({
isSearchExpanded: true
...
...
@@ -53,11 +55,11 @@ class CustomAppBar extends React.Component {
<div
className={classNames(
'
app
-
bar
-
link
-
container
'
, !this.state.isAppBarExpanded &&
'
app
-
bar
-
hide
'
)}>
<Button className={classNames(
'
app
-
bar
-
link
-
button
'
,
'
app
-
bar
-
text
-
color
'
)}
href={
'
https
:
//srct.gmu.edu/'} target="_blank">
href={
'
https
:
//srct.gmu.edu/'} target="_blank"
rel="noopener"
>
About
<
/Button
>
<
Button
className
=
{
classNames
(
'
app-bar-link-button
'
,
'
app-bar-text-color
'
)}
href
=
{
'
https://srct.gmu.edu/contact/
'
}
target
=
"
_blank
"
>
href
=
{
'
https://srct.gmu.edu/contact/
'
}
target
=
"
_blank
"
rel
=
"
noopener
"
>
Feedback
<
/Button
>
<
/div
>
...
...
src/containers/AlertContainer.js
0 → 100644
View file @
c6eb5df3
import
React
from
'
react
'
;
import
{
findDOMNode
}
from
'
react-dom
'
;
import
Button
from
'
material-ui/Button
'
;
import
Popover
from
'
material-ui/Popover
'
;
import
Alert
from
'
../components/Alert
'
;
import
NotificationsIcon
from
'
material-ui-icons/Notifications
'
;
import
{
connect
}
from
'
react-redux
'
;
class
AlertContainer
extends
React
.
Component
{
constructor
()
{
super
();
this
.
state
=
{
isOpen
:
false
,
anchorEl
:
null
};
}
handleOpen
=
()
=>
{
this
.
setState
({
isOpen
:
true
});
};
handleClose
=
()
=>
{
this
.
setState
({
isOpen
:
false
});
};
handleBtnRef
=
(
c
)
=>
{
this
.
setState
({
anchorEl
:
findDOMNode
(
c
)
});
};
isAlertActive
=
(
alert
)
=>
{
const
curDate
=
new
Date
();
const
startDate
=
new
Date
(
alert
.
start_datetime
);
const
endDate
=
new
Date
(
alert
.
end_datetime
);
return
curDate
>
startDate
&&
curDate
<
endDate
;
};
render
()
{
const
{
alerts
}
=
this
.
props
;
return
(
<
div
>
<
Button
fab
mini
color
=
{
'
primary
'
}
ref
=
{
this
.
handleBtnRef
}
onClick
=
{
this
.
handleOpen
}
>
<
NotificationsIcon
/>
<
/Button
>
<
Popover
open
=
{
this
.
state
.
isOpen
}
anchorEl
=
{
this
.
state
.
anchorEl
}
anchorOrigin
=
{{
vertical
:
'
bottom
'
,
horizontal
:
'
center
'
}}
transformOrigin
=
{{
vertical
:
'
top
'
,
horizontal
:
'
center
'
}}
onClose
=
{
this
.
handleClose
}
>
<
div
className
=
{
'
alert-container-popover
'
}
>
{
alerts
.
filter
(
this
.
isAlertActive
).
map
((
alert
)
=>
{
return
(
<
Alert
key
=
{
alert
.
id
}
alert
=
{
alert
}
/
>
);
})}
<
/div
>
<
/Popover
>
<
/div
>
);
}
}
function
mapStateToProps
(
state
)
{
return
{
alerts
:
state
.
alerts
};
}
export
default
connect
(
mapStateToProps
)(
AlertContainer
);
src/containers/Layout.js
View file @
c6eb5df3
...
...
@@ -2,7 +2,6 @@ import React from 'react';
import
{
connect
}
from
'
react-redux
'
;
import
{
setAllFavorites
,
setSelectedFacility
,
setSidebar
}
from
'
../actions/ui
'
;
import
AppBar
from
'
../components/AppBar
'
;
import
AlertContainer
from
'
../components/AlertContainer
'
;
import
Sidebar
from
'
../components/Sidebar
'
;
import
{
getAlerts
,
getFacilities
,
setAlerts
,
setFacilities
,
sortByFavorites
}
from
'
../actions/api
'
;
import
CardContainer
from
'
../components/CardContainer
'
;
...
...
@@ -39,12 +38,11 @@ class Layout extends React.Component {
};
render
()
{
const
{
isSidebarOpen
,
selectedFacility
,
facilities
,
alerts
,
searchTerm
,
campusRegion
,
setSidebar
,
setSelectedFacility
}
=
this
.
props
;
const
{
isSidebarOpen
,
selectedFacility
,
facilities
,
searchTerm
,
campusRegion
,
setSidebar
,
setSelectedFacility
}
=
this
.
props
;
return
(
<
div
className
=
{
'
layout-root
'
}
>
<
AppBar
isOpen
=
{
false
}
/
>
<
AlertContainer
alerts
=
{
alerts
}
/
>
<
div
className
=
{
'
layout-container
'
}
>
<
div
className
=
{
'
layout-main-content
'
}
>
<
div
className
=
{
'
layout-card-container
'
}
>
...
...
src/styles/components/alert.scss
0 → 100644
View file @
c6eb5df3
.alert
{
margin
:
8px
;
padding
:
6px
24px
;
border-radius
:
5px
;
color
:
rgba
(
255
,
255
,
255
,
1
);
display
:
flex
;
flex-wrap
:
wrap
;
align-items
:
center
;
box-shadow
:
0px
3px
5px
-1px
rgba
(
0
,
0
,
0
,
0
.2
)
,
0px
6px
10px
0px
rgba
(
0
,
0
,
0
,
0
.14
)
,
0px
1px
18px
0px
rgba
(
0
,
0
,
0
,
0
.12
);
font-size
:
0
.875rem
;
font-weight
:
400
;
font-family
:
"Roboto"
,
"Helvetica"
,
"Arial"
,
sans-serif
;
line-height
:
1
.46429em
;
}
.alert-link
{
color
:
rgba
(
255
,
255
,
255
,
1
)
!
important
;
}
.alert-info
{
background-color
:
#42A5F5
;
}
.alert-minor
{
background-color
:
#66BB6A
;
}
.alert-major
{
background-color
:
#FFA726
;
}
.alert-emergency
{
background-color
:
#EF5350
;
}
\ No newline at end of file
src/styles/components/alertContainer.scss
deleted
100644 → 0
View file @
0f8bb75e
.notification
{
height
:
auto
!
important
;
.notification-message
{
font-family
:
"Roboto"
,
"-apple-system"
,
"Helvetica"
,
"Arial"
,
sans-serif
;
line-height
:
24px
;
font-size
:
14px
;
font-weight
:
500
;
}
}
@media
screen
and
(
max-width
:
500px
)
{
.notifications-bl
{
width
:
100%
!
important
;
}
}
\ No newline at end of file
src/styles/containers/alertContainer.scss
0 → 100644
View file @
c6eb5df3
.alert-container-popover
{
max-width
:
500px
;
}
\ No newline at end of file
src/styles/whatsOpen.scss
View file @
c6eb5df3
@import
'./variables.scss'
;
@import
'./mixins.scss'
;
/* Components */
@import
'components/alert
Container
'
;
@import
'
./
components/alert'
;
@import
'./components/appBar'
;
@import
'./components/cardContainer'
;
@import
'./components/facilityCategory'
;
...
...
@@ -13,6 +13,7 @@
@import
'./components/textwTitle'
;
@import
'./components/weekHours'
;
/* Containers */
@import
'./containers/alertContainer'
;
@import
'./containers/facilityCard'
;
@import
'./containers/layout'
;
@import
'./containers/searchBar'
;
...
...
src/utils/nameUtils.js
View file @
c6eb5df3
...
...
@@ -16,4 +16,15 @@ export const removeBrackets = (name) => {
}
return
name
;
};
const
linkRegex
=
/
(?:(?:
https
?
|ftp|file
)
:
\/\/
|www
\.
|ftp
\.)(?:\([
-A-Z0-9+&@#
\/
%=~_|$?!:,.
]
*
\)
|
[
-A-Z0-9+&@#
\/
%=~_|$?!:,.
])
*
(?:\([
-A-Z0-9+&@#
\/
%=~_|$?!:,.
]
*
\)
|
[
A-Z0-9+&@#
\/
%=~_|$
])
/igm
;
/**
* Finds where links appear in a string.
*
* @param val The string
* @returns {RegExpExecArray | null}
*/
export
const
findLink
=
(
val
)
=>
{
return
linkRegex
.
exec
(
val
);
};
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment