loading states for notifications

This commit is contained in:
Connor Turland 2018-03-07 18:38:53 -05:00
parent 10359a1f53
commit f35cea5ba6
10 changed files with 58 additions and 17 deletions

View file

@ -4,16 +4,23 @@ import GlobalUI from './index'
const Notifications = { const Notifications = {
notifications: [], notifications: [],
notificationsLoading: false,
unreadNotificationsCount: 0, unreadNotificationsCount: 0,
init: serverData => { init: serverData => {
Notifications.unreadNotificationsCount = serverData.unreadNotificationsCount Notifications.unreadNotificationsCount = serverData.unreadNotificationsCount
}, },
fetchNotifications: render => { fetchNotifications: render => {
Notifications.notificationsLoading = true
render()
$.ajax({ $.ajax({
url: '/notifications.json', url: '/notifications.json',
success: function(data) { success: function(data) {
Notifications.notifications = data Notifications.notifications = data
Notifications.notificationsLoading = false
render() render()
},
error: function() {
GlobalUI.notifyUser('There was an error fetching notifications')
} }
}) })
}, },

View file

@ -53,7 +53,6 @@ const ReactApp = {
switch (pathname.split('/')[1]) { switch (pathname.split('/')[1]) {
case '': case '':
if (Active.Mapper && Active.Mapper.id) { if (Active.Mapper && Active.Mapper.id) {
$('#yield').hide()
ExploreMaps.updateFromPath(pathname) ExploreMaps.updateFromPath(pathname)
self.mapId = null self.mapId = null
Active.Map = null Active.Map = null
@ -61,7 +60,6 @@ const ReactApp = {
} }
break break
case 'explore': case 'explore':
$('#yield').hide()
ExploreMaps.updateFromPath(pathname) ExploreMaps.updateFromPath(pathname)
self.mapId = null self.mapId = null
self.topicId = null self.topicId = null
@ -69,21 +67,18 @@ const ReactApp = {
Active.Topic = null Active.Topic = null
break break
case 'topics': case 'topics':
$('#yield').hide()
Active.Map = null Active.Map = null
self.mapId = null self.mapId = null
self.topicId = pathname.split('/')[2] self.topicId = pathname.split('/')[2]
break break
case 'maps': case 'maps':
if (!pathname.includes('request_access')) { if (!pathname.includes('request_access')) {
$('#yield').hide()
Active.Topic = null Active.Topic = null
self.topicId = null self.topicId = null
self.mapId = pathname.split('/')[2] self.mapId = pathname.split('/')[2]
} }
break break
default: default:
$('#yield').show()
break break
} }
self.render() self.render()
@ -108,6 +103,7 @@ const ReactApp = {
openInviteLightbox: () => self.openLightbox('invite'), openInviteLightbox: () => self.openLightbox('invite'),
serverData: self.serverData, serverData: self.serverData,
notifications: Notifications.notifications, notifications: Notifications.notifications,
notificationsLoading: Notifications.notificationsLoading,
fetchNotifications: apply(Notifications.fetchNotifications, ReactApp.render), fetchNotifications: apply(Notifications.fetchNotifications, ReactApp.render),
fetchNotification: apply(Notifications.fetchNotification, ReactApp.render), fetchNotification: apply(Notifications.fetchNotification, ReactApp.render),
markAsRead: apply(Notifications.markAsRead, ReactApp.render), markAsRead: apply(Notifications.markAsRead, ReactApp.render),

View file

@ -9,6 +9,7 @@ import Loading from './Loading'
class NotificationBox extends Component { class NotificationBox extends Component {
static propTypes = { static propTypes = {
notifications: PropTypes.array, notifications: PropTypes.array,
loading: PropTypes.bool.isRequired,
fetchNotifications: PropTypes.func.isRequired, fetchNotifications: PropTypes.func.isRequired,
toggleNotificationsBox: PropTypes.func.isRequired, toggleNotificationsBox: PropTypes.func.isRequired,
markAsRead: PropTypes.func.isRequired, markAsRead: PropTypes.func.isRequired,
@ -60,11 +61,11 @@ class NotificationBox extends Component {
} }
render = () => { render = () => {
const { notifications } = this.props const { loading } = this.props
return <div className='notificationsBox'> return <div className='notificationsBox'>
<div className='notificationsBoxTriangle' /> <div className='notificationsBoxTriangle' />
<ul className='notifications'> <ul className='notifications'>
{notifications ? this.showNotifications() : this.showLoading()} {loading ? this.showLoading() : this.showNotifications()}
</ul> </ul>
</div> </div>
} }

View file

@ -50,7 +50,7 @@ class UpperRightUI extends Component {
render () { render () {
const { currentUser, signInPage, unreadNotificationsCount, const { currentUser, signInPage, unreadNotificationsCount,
notifications, fetchNotifications, openInviteLightbox, notifications, fetchNotifications, openInviteLightbox,
markAsRead, markAsUnread } = this.props markAsRead, markAsUnread, notificationsLoading } = this.props
const { accountBoxOpen, notificationsBoxOpen } = this.state const { accountBoxOpen, notificationsBoxOpen } = this.state
return <div className="upperRightUI"> return <div className="upperRightUI">
{currentUser && <a href="/maps/new" target="_blank" className="addMap upperRightEl upperRightIcon"> {currentUser && <a href="/maps/new" target="_blank" className="addMap upperRightEl upperRightIcon">
@ -63,6 +63,7 @@ class UpperRightUI extends Component {
unreadNotificationsCount={unreadNotificationsCount} unreadNotificationsCount={unreadNotificationsCount}
toggleNotificationsBox={this.toggleNotificationsBox}/> toggleNotificationsBox={this.toggleNotificationsBox}/>
{notificationsBoxOpen && <NotificationBox {notificationsBoxOpen && <NotificationBox
loading={notificationsLoading}
notifications={notifications} notifications={notifications}
fetchNotifications={fetchNotifications} fetchNotifications={fetchNotifications}
markAsRead={markAsRead} markAsRead={markAsRead}

View file

@ -1,3 +1,5 @@
// these come from mailboxer.rb in the api repo
export const MAP_ACCESS_REQUEST = 'ACCESS_REQUEST' export const MAP_ACCESS_REQUEST = 'ACCESS_REQUEST'
export const MAP_ACCESS_APPROVED = 'ACCESS_APPROVED' export const MAP_ACCESS_APPROVED = 'ACCESS_APPROVED'
export const MAP_INVITE_TO_EDIT = 'INVITE_TO_EDIT' export const MAP_INVITE_TO_EDIT = 'INVITE_TO_EDIT'

View file

@ -43,7 +43,7 @@ class App extends Component {
mobile, mobileTitle, mobileTitleWidth, mobileTitleClick, location, mobile, mobileTitle, mobileTitleWidth, mobileTitleClick, location,
map, userRequested, requestAnswered, requestApproved, serverData, map, userRequested, requestAnswered, requestApproved, serverData,
onRequestAccess, notifications, fetchNotifications, onRequestAccess, notifications, fetchNotifications,
markAsRead, markAsUnread } = this.props markAsRead, markAsUnread, notificationsLoading } = this.props
const { pathname } = location || {} const { pathname } = location || {}
// this fixes a bug that happens otherwise when you logout // this fixes a bug that happens otherwise when you logout
const currentUser = this.props.currentUser && this.props.currentUser.id ? this.props.currentUser : null const currentUser = this.props.currentUser && this.props.currentUser.id ? this.props.currentUser : null
@ -64,6 +64,7 @@ class App extends Component {
{!mobile && <UpperRightUI currentUser={currentUser} {!mobile && <UpperRightUI currentUser={currentUser}
unreadNotificationsCount={unreadNotificationsCount} unreadNotificationsCount={unreadNotificationsCount}
notifications={notifications} notifications={notifications}
notificationsLoading={notificationsLoading}
fetchNotifications={fetchNotifications} fetchNotifications={fetchNotifications}
markAsRead={markAsRead} markAsRead={markAsRead}
markAsUnread={markAsUnread} markAsUnread={markAsUnread}

View file

@ -4,6 +4,7 @@ import { throttle } from 'lodash'
import Header from './Header' import Header from './Header'
import MapperCard from './MapperCard' import MapperCard from './MapperCard'
import MapCard from './MapCard' import MapCard from './MapCard'
import LoadingPage from '../helpers/LoadingPage'
class Maps extends Component { class Maps extends Component {
static propTypes = { static propTypes = {
@ -45,7 +46,17 @@ class Maps extends Component {
const { mobile, maps, mapsWidth, currentUser, juntoState, pending, section, user, onStar, onRequest, onMapFollow } = this.props const { mobile, maps, mapsWidth, currentUser, juntoState, pending, section, user, onStar, onRequest, onMapFollow } = this.props
const style = { width: mapsWidth + 'px' } const style = { width: mapsWidth + 'px' }
if (!maps) return null // do loading here instead if (!maps) {
return (
<div>
<LoadingPage />
<Header signedIn={ !!currentUser }
section={ section }
user={ user }
/>
</div>
)
}
return ( return (
<div> <div>

View file

@ -3,6 +3,7 @@ import { Link } from 'react-router'
import { MAP_ACCESS_REQUEST } from '../../constants' import { MAP_ACCESS_REQUEST } from '../../constants'
import NotificationsHeader from './NotificationsHeader' import NotificationsHeader from './NotificationsHeader'
import LoadingPage from '../helpers/LoadingPage'
import Loading from '../../components/Loading' import Loading from '../../components/Loading'
import NotificationBody from '../../components/NotificationBody' import NotificationBody from '../../components/NotificationBody'
@ -25,11 +26,7 @@ class NotificationPage extends Component {
if (!notification) { if (!notification) {
return ( return (
<div> <div>
<div id="yield"> <LoadingPage />
<div className="centerContent withPadding back">
<Loading />
</div>
</div>
<NotificationsHeader /> <NotificationsHeader />
</div> </div>
) )

View file

@ -1,6 +1,7 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import { Link } from 'react-router' import { Link } from 'react-router'
import LoadingPage from '../helpers/LoadingPage'
import Notification from '../../components/Notification' import Notification from '../../components/Notification'
import { import {
@ -10,7 +11,6 @@ import {
} from '../../constants' } from '../../constants'
import NotificationsHeader from './NotificationsHeader' import NotificationsHeader from './NotificationsHeader'
// these come from mailboxer.rb in the api repo
const BLACKLIST = [MAP_ACCESS_REQUEST, MAP_ACCESS_APPROVED, MAP_INVITE_TO_EDIT] const BLACKLIST = [MAP_ACCESS_REQUEST, MAP_ACCESS_APPROVED, MAP_INVITE_TO_EDIT]
/* TODO!! /* TODO!!
@ -25,8 +25,16 @@ class Notifications extends Component {
} }
render = () => { render = () => {
const { markAsRead, markAsUnread } = this.props const { notificationsLoading, markAsRead, markAsUnread } = this.props
const notifications = (this.props.notifications || []).filter(n => !(BLACKLIST.indexOf(n.type) > -1 && (!n.data.object || !n.data.map))) const notifications = (this.props.notifications || []).filter(n => !(BLACKLIST.indexOf(n.type) > -1 && (!n.data.object || !n.data.map)))
if (notificationsLoading) {
return (
<div>
<LoadingPage />
<NotificationsHeader />
</div>
)
}
return ( return (
<div> <div>
<div id="yield"> <div id="yield">

View file

@ -0,0 +1,17 @@
import React, { Component } from 'react'
import Loading from '../../components/Loading'
class LoadingPage extends Component {
render = () => {
return (
<div id="yield">
<div className="centerContent withPadding back">
<Loading />
</div>
</div>
)
}
}
export default LoadingPage