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
869e5b34
Commit
869e5b34
authored
Jan 29, 2020
by
Andrew Hrdy
Browse files
Convert all class components to functional components
parent
df6d22d3
Changes
27
Hide whitespace changes
Inline
Side-by-side
src/components/Alert.tsx
View file @
869e5b34
...
@@ -2,25 +2,21 @@ import * as React from 'react';
...
@@ -2,25 +2,21 @@ import * as React from 'react';
import
*
as
classNames
from
'
classnames
'
;
import
*
as
classNames
from
'
classnames
'
;
import
{
findLink
}
from
'
../utils/nameUtils
'
;
import
{
findLink
}
from
'
../utils/nameUtils
'
;
import
{
IAlert
}
from
'
../models/alert.model
'
;
import
{
IAlert
}
from
'
../models/alert.model
'
;
import
Chip
from
'
@material-ui/core/Chip
'
;
import
Button
from
'
@material-ui/core/Button
'
;
import
ArrowForwardIcon
from
'
@material-ui/icons/ArrowForward
'
;
import
ArrowForwardIcon
from
'
@material-ui/icons/ArrowForward
'
;
import
{
Chip
,
Button
}
from
'
@material-ui/core
'
;
class
Alert
extends
React
.
Component
<
AlertProps
>
{
interface
AlertProps
{
alert
:
IAlert
;
}
constructor
(
props
:
AlertProps
)
{
export
default
({
alert
}:
AlertProps
)
=>
{
super
(
props
);
}
/**
/**
* Converts the alert's urgency tag to the corresponding
* Converts the alert's urgency tag to the corresponding
* css class.
* css class.
*
* @memberof Alert
*/
*/
getUrgencyClass
=
()
=>
{
const
getUrgencyClass
=
()
=>
{
switch
(
this
.
props
.
alert
.
urgency_tag
)
{
switch
(
alert
.
urgency_tag
)
{
case
'
emergency
'
:
case
'
emergency
'
:
return
'
alert-emergency
'
;
return
'
alert-emergency
'
;
case
'
major
'
:
case
'
major
'
:
...
@@ -31,16 +27,14 @@ class Alert extends React.Component<AlertProps> {
...
@@ -31,16 +27,14 @@ class Alert extends React.Component<AlertProps> {
default
:
default
:
return
'
alert-info
'
;
return
'
alert-info
'
;
}
}
}
}
;
/**
/**
* Converts the alert's text body to proper JSX
* Converts the alert's text body to proper JSX
*
*
* @memberof Alert
* @memberof Alert
*/
*/
getBody
=
()
=>
{
const
getBody
=
()
=>
{
const
alert
:
IAlert
=
this
.
props
.
alert
;
const
links
=
findLink
(
alert
.
body
);
const
links
=
findLink
(
alert
.
body
);
if
(
!
links
)
{
if
(
!
links
)
{
...
@@ -58,41 +52,31 @@ class Alert extends React.Component<AlertProps> {
...
@@ -58,41 +52,31 @@ class Alert extends React.Component<AlertProps> {
{
alert
.
body
.
substring
(
links
.
index
+
links
[
0
].
length
)
}
{
alert
.
body
.
substring
(
links
.
index
+
links
[
0
].
length
)
}
</
span
>
</
span
>
);
);
}
};
getChipLabel
=
()
=>
this
.
props
.
alert
.
urgency_tag
.
charAt
(
0
).
toUpperCase
()
+
this
.
props
.
alert
.
urgency_tag
.
slice
(
1
);
render
()
{
const
getChipLabel
=
()
=>
alert
.
urgency_tag
.
charAt
(
0
).
toUpperCase
()
+
alert
.
urgency_tag
.
slice
(
1
);
const
alert
:
IAlert
=
this
.
props
.
alert
;
return
(
return
(
<
div
className
=
{
'
alert
'
}
>
<
div
className
=
{
'
alert
'
}
>
<
div
className
=
{
'
alert-subject-container
'
}
>
<
div
className
=
{
'
alert-subject-container
'
}
>
<
h3
className
=
{
'
alert-subject
'
}
>
{
alert
.
subject
}
</
h3
>
<
h3
className
=
{
'
alert-subject
'
}
>
{
alert
.
subject
}
</
h3
>
<
Chip
label
=
{
this
.
getChipLabel
()
}
className
=
{
classNames
(
'
alert-urgency-chip
'
,
this
.
getUrgencyClass
())
}
/>
<
Chip
label
=
{
getChipLabel
()
}
className
=
{
classNames
(
'
alert-urgency-chip
'
,
getUrgencyClass
())
}
/>
</
div
>
{
this
.
getBody
()
}
{
alert
.
url
&&
<
span
className
=
{
'
alert-url-container
'
}
>
<
Button
size
=
{
'
small
'
}
href
=
{
alert
.
url
}
target
=
"_blank"
rel
=
"noopener noreferrer"
classes
=
{
{
root
:
'
alert-url-button-root
'
}
}
>
More Information
<
ArrowForwardIcon
/>
</
Button
>
</
span
>
}
</
div
>
</
div
>
);
}
}
export
interface
AlertProps
{
{
getBody
()
}
alert
:
IAlert
;
}
export
default
Alert
;
{
\ No newline at end of file
alert
.
url
&&
<
span
className
=
{
'
alert-url-container
'
}
>
<
Button
size
=
{
'
small
'
}
href
=
{
alert
.
url
}
target
=
"_blank"
rel
=
"noopener noreferrer"
classes
=
{
{
root
:
'
alert-url-button-root
'
}
}
>
More Information
<
ArrowForwardIcon
/>
</
Button
>
</
span
>
}
</
div
>
);
};
\ No newline at end of file
src/components/AppBar.tsx
View file @
869e5b34
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
*
as
classNames
from
'
classnames
'
;
import
*
as
classNames
from
'
classnames
'
;
import
SearchBar
from
'
../containers/SearchBar
'
;
import
SearchBar
from
'
../containers/SearchBar
'
;
import
AlertContainer
from
'
../containers/AlertContainer
'
;
import
AlertContainer
from
'
../containers/AlertContainer
'
;
import
{
AppBar
,
Toolbar
,
Typography
,
Button
}
from
'
@material-ui/core
'
;
import
AppBar
from
'
@material-ui/core/AppBar
'
;
interface
AppBarProps
{
import
Toolbar
from
'
@material-ui/core/Toolbar
'
;
import
Typography
from
'
@material-ui/core/Typography
'
;
import
Button
from
'
@material-ui/core/Button
'
;
class
CustomAppBar
extends
React
.
Component
<
CustomAppBarProps
,
CustomAppBarState
>
{
constructor
(
props
:
CustomAppBarProps
)
{
super
(
props
);
this
.
state
=
{
isSearchExpanded
:
false
};
}
render
()
{
const
{
isMobile
}
=
this
.
props
;
return
(
<
div
>
<
AppBar
position
=
"absolute"
className
=
{
classNames
(
'
app-bar
'
,
this
.
state
.
isSearchExpanded
&&
'
app-bar-search-expanded
'
,
isMobile
&&
'
app-bar-mobile
'
)
}
>
<
Toolbar
className
=
{
'
app-bar-tool-bar
'
}
>
<
div
className
=
{
'
app-bar-logo-name
'
}
>
<
img
src
=
{
'
favicon.png
'
}
className
=
{
'
app-bar-logo
'
}
/>
<
Typography
variant
=
"h6"
className
=
{
classNames
(
'
app-bar-title
'
,
'
app-bar-text-color
'
)
}
>
What's Open
</
Typography
>
</
div
>
<
div
className
=
{
'
app-bar-right-section
'
}
>
<
div
className
=
{
'
app-bar-alert-container
'
}
>
<
AlertContainer
/>
</
div
>
<
SearchBar
onSearchExpand
=
{
()
=>
this
.
setState
({
isSearchExpanded
:
true
})
}
onSearchCollapse
=
{
()
=>
this
.
setState
({
isSearchExpanded
:
false
})
}
/>
</
div
>
<
div
className
=
{
'
app-bar-link-container
'
}
>
<
Button
className
=
{
classNames
(
'
app-bar-link-button
'
,
'
app-bar-text-color
'
)
}
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"
rel
=
"noopener"
>
Feedback
</
Button
>
</
div
>
</
Toolbar
>
</
AppBar
>
</
div
>
);
}
}
export
interface
CustomAppBarProps
{
isMobile
?:
boolean
;
isMobile
?:
boolean
;
}
}
export
interface
CustomAppBarState
{
export
default
({
isMobile
}:
AppBarProps
)
=>
{
isSearchExpanded
:
boolean
;
const
[
isSearchExpanded
,
setIsSearchExpanded
]
=
React
.
useState
<
boolean
>
(
false
);
}
return
(
<
div
>
<
AppBar
position
=
"absolute"
className
=
{
classNames
(
'
app-bar
'
,
isSearchExpanded
&&
'
app-bar-search-expanded
'
,
isMobile
&&
'
app-bar-mobile
'
)
}
>
<
Toolbar
className
=
{
'
app-bar-tool-bar
'
}
>
<
div
className
=
{
'
app-bar-logo-name
'
}
>
<
img
src
=
{
'
favicon.png
'
}
className
=
{
'
app-bar-logo
'
}
/>
<
Typography
variant
=
"h6"
className
=
{
classNames
(
'
app-bar-title
'
,
'
app-bar-text-color
'
)
}
>
What's Open
</
Typography
>
</
div
>
<
div
className
=
{
'
app-bar-right-section
'
}
>
<
div
className
=
{
'
app-bar-alert-container
'
}
>
<
AlertContainer
/>
</
div
>
export
default
CustomAppBar
;
<
SearchBar
onSearchExpand
=
{
()
=>
setIsSearchExpanded
(
true
)
}
onSearchCollapse
=
{
()
=>
setIsSearchExpanded
(
false
)
}
/>
</
div
>
<
div
className
=
{
'
app-bar-link-container
'
}
>
<
Button
className
=
{
classNames
(
'
app-bar-link-button
'
,
'
app-bar-text-color
'
)
}
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"
rel
=
"noopener"
>
Feedback
</
Button
>
</
div
>
</
Toolbar
>
</
AppBar
>
</
div
>
);
};
\ No newline at end of file
src/components/CardContainer.tsx
View file @
869e5b34
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
IFacility
,
CampusRegion
}
from
'
../models/facility.model
'
;
import
{
IFacility
}
from
'
../models/facility.model
'
;
import
FacilityCard
from
'
../containers/FacilityCard
'
;
import
FacilityCard
from
'
../containers/FacilityCard
'
;
import
{
Grid
}
from
'
@material-ui/core
'
;
import
Grid
from
'
@material-ui/core/Grid
'
;
interface
CardContainerProps
{
class
CardContainer
extends
React
.
Component
<
CardContainerProps
>
{
constructor
(
props
:
CardContainerProps
)
{
super
(
props
);
}
render
()
{
const
{
facilities
,
showFavoriteIcons
}
=
this
.
props
;
return
(
<
Grid
container
=
{
true
}
className
=
{
'
card-container-root
'
}
spacing
=
{
3
}
justify
=
{
'
center
'
}
alignItems
=
{
'
flex-end
'
}
>
{
facilities
.
map
(
item
=>
(
<
Grid
key
=
{
item
.
slug
}
item
=
{
true
}
>
<
FacilityCard
facility
=
{
item
}
showFavoriteIcon
=
{
showFavoriteIcons
}
/>
</
Grid
>
))
}
</
Grid
>
);
}
}
export
interface
CardContainerProps
{
facilities
:
IFacility
[];
facilities
:
IFacility
[];
showFavoriteIcons
:
boolean
;
showFavoriteIcons
:
boolean
;
}
}
export
default
CardContainer
;
export
default
({
facilities
,
showFavoriteIcons
}:
CardContainerProps
)
=>
{
\ No newline at end of file
return
(
<
Grid
container
=
{
true
}
className
=
{
'
card-container-root
'
}
spacing
=
{
3
}
justify
=
{
'
center
'
}
alignItems
=
{
'
flex-end
'
}
>
{
facilities
.
map
(
item
=>
(
<
Grid
key
=
{
item
.
slug
}
item
=
{
true
}
>
<
FacilityCard
facility
=
{
item
}
showFavoriteIcon
=
{
showFavoriteIcons
}
/>
</
Grid
>
))
}
</
Grid
>
);
};
\ No newline at end of file
src/components/FacilityCategory.tsx
View file @
869e5b34
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
IFacilityCategory
}
from
'
../models/facility.model
'
;
import
{
IFacilityCategory
}
from
'
../models/facility.model
'
;
import
{
Typography
}
from
'
@material-ui/core
'
;
import
Typography
from
'
@material-ui/core/Typography
'
;
class
FacilityCategory
extends
React
.
Component
<
FacilityCategoryProps
>
{
constructor
(
props
:
FacilityCategoryProps
)
{
super
(
props
);
}
render
()
{
return
(
<
div
className
=
{
'
facility-category-wrapper
'
}
>
<
Typography
variant
=
{
'
body1
'
}
noWrap
=
{
true
}
>
{
this
.
props
.
category
.
name
}
</
Typography
>
</
div
>
);
}
}
export
interface
FacilityCategoryProps
{
export
interface
FacilityCategoryProps
{
category
:
IFacilityCategory
;
category
:
IFacilityCategory
;
}
}
export
default
FacilityCategory
;
export
default
({
category
}:
FacilityCategoryProps
)
=>
{
\ No newline at end of file
return
(
<
div
className
=
{
'
facility-category-wrapper
'
}
>
<
Typography
variant
=
{
'
body1
'
}
noWrap
=
{
true
}
>
{
category
.
name
}
</
Typography
>
</
div
>
);
};
\ No newline at end of file
src/components/FacilityStatus.tsx
View file @
869e5b34
...
@@ -2,25 +2,23 @@ import * as React from 'react';
...
@@ -2,25 +2,23 @@ import * as React from 'react';
import
*
as
classNames
from
'
classnames
'
;
import
*
as
classNames
from
'
classnames
'
;
import
FacilityUtils
from
'
../utils/facilityUtils
'
;
import
FacilityUtils
from
'
../utils/facilityUtils
'
;
import
{
IFacility
}
from
'
../models/facility.model
'
;
import
{
IFacility
}
from
'
../models/facility.model
'
;
import
{
Typography
}
from
'
@material-ui/core
'
;
import
Typography
from
'
@material-ui/core/Typography
'
;
interface
FacilityStatusProps
{
facility
:
IFacility
;
class
FacilityStatus
extends
React
.
Component
<
FacilityStatusProps
>
{
}
constructor
(
props
:
FacilityStatusProps
)
{
super
(
props
);
}
export
default
({
facility
}:
FacilityStatusProps
)
=>
{
/**
/**
* Generates information about the facility's status.
* Generates information about the facility's status.
*
*
* @returns {{label: string, isOpen: boolean}} Information about the facility.
* @returns {{label: string, isOpen: boolean}} Information about the facility.
*/
*/
generateStatusInfo
=
()
=>
{
const
generateStatusInfo
=
()
=>
{
let
label
;
let
label
;
let
isOpen
;
let
isOpen
;
if
(
FacilityUtils
.
isFacilityOpen
(
this
.
props
.
facility
))
{
if
(
FacilityUtils
.
isFacilityOpen
(
facility
))
{
label
=
'
OPEN
'
;
label
=
'
OPEN
'
;
isOpen
=
true
;
isOpen
=
true
;
}
else
{
}
else
{
...
@@ -32,22 +30,14 @@ class FacilityStatus extends React.Component<FacilityStatusProps> {
...
@@ -32,22 +30,14 @@ class FacilityStatus extends React.Component<FacilityStatusProps> {
label
:
label
,
label
:
label
,
isOpen
:
isOpen
isOpen
:
isOpen
};
};
}
};
render
()
{
const
statusInfo
=
this
.
generateStatusInfo
();
return
(
const
statusInfo
=
generateStatusInfo
();
<
Typography
variant
=
{
'
caption
'
}
className
=
{
classNames
(
'
facility-status-text
'
,
statusInfo
.
isOpen
?
'
facility-status-open
'
:
'
facility-status-closed
'
)
}
>
{
statusInfo
.
label
}
</
Typography
>
);
}
}
export
interface
FacilityStatusProps
{
facility
:
IFacility
;
}
export
default
FacilityStatus
;
return
(
\ No newline at end of file
<
Typography
variant
=
{
'
caption
'
}
className
=
{
classNames
(
'
facility-status-text
'
,
statusInfo
.
isOpen
?
'
facility-status-open
'
:
'
facility-status-closed
'
)
}
>
{
statusInfo
.
label
}
</
Typography
>
);
};
\ No newline at end of file
src/components/FavoriteButton.tsx
View file @
869e5b34
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
*
as
classNames
from
'
classnames
'
;
import
*
as
classNames
from
'
classnames
'
;
import
{
Tooltip
}
from
'
@material-ui/core
'
;
import
FavoriteBorderIcon
from
'
@material-ui/icons/FavoriteBorder
'
;
import
FavoriteBorderIcon
from
'
@material-ui/icons/FavoriteBorder
'
;
import
FavoriteIcon
from
'
@material-ui/icons/Favorite
'
;
import
FavoriteIcon
from
'
@material-ui/icons/Favorite
'
;
import
Tooltip
from
'
@material-ui/core/Tooltip
'
;
import
{
trackPiwikEvent
}
from
'
../piwik/piwik
'
;
import
{
trackPiwikEvent
}
from
'
../piwik/piwik
'
;
class
FavoriteButton
extends
React
.
Component
<
FavoriteButtonProps
,
FavoriteButtonState
>
{
interface
FavoriteButtonProps
{
slug
:
string
;
initialState
:
boolean
;
addFavoriteFacility
:
(
slug
:
string
)
=>
void
;
removeFavoriteFacility
:
(
slug
:
string
)
=>
void
;
}
constructor
(
props
:
FavoriteButtonProps
)
{
export
default
({
slug
,
initialState
,
addFavoriteFacility
,
removeFavoriteFacility
}
:
FavoriteButtonProps
)
=>
{
super
(
props
);
const
[
isFavorite
,
setIsFavorite
]
=
React
.
useState
<
boolean
>
(
initialState
);
this
.
state
=
{
const
handleClick
=
(
event
:
React
.
MouseEvent
)
=>
{
isFavorite
:
props
.
initialState
};
}
handleClick
=
(
event
:
React
.
MouseEvent
)
=>
{
event
.
stopPropagation
();
// Stops the card from being selected in the sidebar.
event
.
stopPropagation
();
// Stops the card from being selected in the sidebar.
event
.
preventDefault
();
// Also stops the card from being selected in the sidebar.
event
.
preventDefault
();
// Also stops the card from being selected in the sidebar.
const
newState
=
!
this
.
state
.
isFavorite
;
const
newState
=
!
isFavorite
;
this
.
setState
({
setIsFavorite
(
newState
);
isFavorite
:
newState
});
if
(
!
newState
)
{
if
(
!
newState
)
{
trackPiwikEvent
(
'
card-action
'
,
'
un-favorite
'
);
trackPiwikEvent
(
'
card-action
'
,
'
un-favorite
'
);
setTimeout
(()
=>
{
setTimeout
(()
=>
{
this
.
props
.
removeFavoriteFacility
(
this
.
props
.
slug
);
removeFavoriteFacility
(
slug
);
},
0
);
},
0
);
}
else
{
}
else
{
trackPiwikEvent
(
'
card-action
'
,
'
favorite
'
);
trackPiwikEvent
(
'
card-action
'
,
'
favorite
'
);
setTimeout
(()
=>
{
setTimeout
(()
=>
{
this
.
props
.
addFavoriteFacility
(
this
.
props
.
slug
);
addFavoriteFacility
(
slug
);
},
0
);
},
0
);
}
}
}
};
render
()
{
if
(
this
.
state
.
isFavorite
)
{
return
(
<
Tooltip
title
=
"Remove Favorite"
>
<
FavoriteIcon
onClick
=
{
this
.
handleClick
}
className
=
{
classNames
(
'
favorite-button-heart
'
,
'
favorite-button-heart-favorited
'
)
}
/>
</
Tooltip
>
);
}
if
(
isFavorite
)
{
return
(
return
(
<
Tooltip
title
=
"
Add
Favorite"
>
<
Tooltip
title
=
"
Remove
Favorite"
>
<
Favorite
Border
Icon
onClick
=
{
this
.
handleClick
}
<
FavoriteIcon
onClick
=
{
handleClick
}
className
=
{
classNames
(
'
favorite-button-heart
'
)
}
/>
className
=
{
classNames
(
'
favorite-button-heart
'
,
'
favorite-button-heart-favorited
'
)
}
/>
</
Tooltip
>
</
Tooltip
>
);
);
}
}
}
export
interface
FavoriteButtonProps
{
slug
:
string
;
initialState
:
boolean
;
addFavoriteFacility
:
(
slug
:
string
)
=>
void
;
removeFavoriteFacility
:
(
slug
:
string
)
=>
void
;
}
interface
FavoriteButtonState
{
isFavorite
:
boolean
;
}
export
default
FavoriteButton
;
return
(
\ No newline at end of file
<
Tooltip
title
=
"Add Favorite"
>
<
FavoriteBorderIcon
onClick
=
{
handleClick
}
className
=
{
classNames
(
'
favorite-button-heart
'
)
}
/>
</
Tooltip
>
);
};
\ No newline at end of file
src/components/LoadingSpinner.tsx
View file @
869e5b34
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
CircularProgress
,
Typography
}
from
'
@material-ui/core
'
;
import
{
CircularProgress
,
Typography
}
from
'
@material-ui/core
'
;
const
LoadingSpinner
=
()
=>
(
export
default
()
=>
(
<
div
className
=
{
'
loading-spinner-container
'
}
>
<
div
className
=
{
'
loading-spinner-container
'
}
>
<
CircularProgress
className
=
{
'
loading-spinner
'
}
/>
<
CircularProgress
className
=
{
'
loading-spinner
'
}
/>
<
Typography
className
=
{
'
loading-text
'
}
variant
=
{
'
h6
'
}
>
<
Typography
className
=
{
'
loading-text
'
}
variant
=
{
'
h6
'
}
>
Loading
Loading
</
Typography
>
</
Typography
>
</
div
>
</
div
>
);
);
\ No newline at end of file
export
default
LoadingSpinner
;
\ No newline at end of file
src/components/Sidebar.tsx
View file @
869e5b34
...
@@ -2,66 +2,48 @@ import * as React from 'react';
...
@@ -2,66 +2,48 @@ import * as React from 'react';
import
{
removeBrackets
}
from
'
../utils/nameUtils
'
;
import
{
removeBrackets
}
from
'
../utils/nameUtils
'
;
import
*
as
phoneFormatter
from
'
phone-formatter
'
;
import
*
as
phoneFormatter
from
'
phone-formatter
'
;
import
{
IFacility
}
from
'
../models/facility.model
'
;
import
{
IFacility
}
from
'
../models/facility.model
'
;
import
TextwTitle
from
'
./TextwTitle
'
;
import
TextwTitle
from
'
./TextwTitle
'
;
import
WeekHours
from
'
./WeekHours
'
;
import
WeekHours
from
'
./WeekHours
'
;
import
{
Paper
,
Avatar
,
Typography
,
Divider
,
IconButton
}
from
'
@material-ui/core
'
;
import
Paper
from
'
@material-ui/core/Paper
'
;
import
Avatar
from
'
@material-ui/core/Avatar
'
;
import
Typography
from
'
@material-ui/core/Typography
'
;