notifications
This commit is contained in:
parent
cba83c0011
commit
10359a1f53
11 changed files with 232 additions and 228 deletions
|
@ -26,6 +26,9 @@ Checklist
|
||||||
- [x] Fix images referenced in the JS
|
- [x] Fix images referenced in the JS
|
||||||
- [x] Figure out how authentication of requests from the frontend to the API works
|
- [x] Figure out how authentication of requests from the frontend to the API works
|
||||||
- [x] Figure out how to combine the nodejs realtime server into server.js
|
- [x] Figure out how to combine the nodejs realtime server into server.js
|
||||||
|
- [ ] Notifications: make sure loading states are working for popup and page
|
||||||
|
- [ ] Notifications: make sure notifications either look nice, or redirect
|
||||||
|
- [ ] Notifications: pagination
|
||||||
- [ ] Get actioncable working
|
- [ ] Get actioncable working
|
||||||
- [ ] Request unreadNotificationCount
|
- [ ] Request unreadNotificationCount
|
||||||
- [ ] Request invite code
|
- [ ] Request invite code
|
||||||
|
@ -34,8 +37,8 @@ Checklist
|
||||||
- [ ] Fix Request An Invite page
|
- [ ] Fix Request An Invite page
|
||||||
- [ ] Make 'new map' action work
|
- [ ] Make 'new map' action work
|
||||||
- [ ] Modify the remaining rails templates into JSX templates
|
- [ ] Modify the remaining rails templates into JSX templates
|
||||||
- [ ] notifications list
|
- [x] notifications list
|
||||||
- [ ] notification page
|
- [x] notification page
|
||||||
- [ ] list metacodes
|
- [ ] list metacodes
|
||||||
- [ ] new metacode
|
- [ ] new metacode
|
||||||
- [ ] edit metacode
|
- [ ] edit metacode
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
/* global $ */
|
/* global $ */
|
||||||
|
import { findIndex } from 'lodash'
|
||||||
import GlobalUI from './index'
|
import GlobalUI from './index'
|
||||||
|
|
||||||
const Notifications = {
|
const Notifications = {
|
||||||
notifications: null,
|
notifications: [],
|
||||||
unreadNotificationsCount: 0,
|
unreadNotificationsCount: 0,
|
||||||
init: serverData => {
|
init: serverData => {
|
||||||
Notifications.unreadNotificationsCount = serverData.unreadNotificationsCount
|
Notifications.unreadNotificationsCount = serverData.unreadNotificationsCount
|
||||||
},
|
},
|
||||||
fetch: render => {
|
fetchNotifications: render => {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/notifications.json',
|
url: '/notifications.json',
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
|
@ -16,6 +17,25 @@ const Notifications = {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
fetchNotification: (render, id) => {
|
||||||
|
$.ajax({
|
||||||
|
url: `/notifications/${id}.json`,
|
||||||
|
success: function(data) {
|
||||||
|
const index = findIndex(Notifications.notifications, n => n.id === data.id)
|
||||||
|
if (index === -1) {
|
||||||
|
// notification not loaded yet, insert it at the start
|
||||||
|
Notifications.notifications.unshift(data)
|
||||||
|
} else {
|
||||||
|
// notification there, replace it
|
||||||
|
Notifications.notifications[index] = data
|
||||||
|
}
|
||||||
|
render()
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
GlobalUI.notifyUser('There was an error fetching that notification')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
incrementUnread: (render) => {
|
incrementUnread: (render) => {
|
||||||
Notifications.unreadNotificationsCount++
|
Notifications.unreadNotificationsCount++
|
||||||
render()
|
render()
|
||||||
|
@ -54,7 +74,7 @@ const Notifications = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function() {
|
||||||
GlobalUI.notifyUser('There was an error marking that notification as read')
|
GlobalUI.notifyUser('There was an error marking that notification as unread')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,8 @@ const ReactApp = {
|
||||||
openInviteLightbox: () => self.openLightbox('invite'),
|
openInviteLightbox: () => self.openLightbox('invite'),
|
||||||
serverData: self.serverData,
|
serverData: self.serverData,
|
||||||
notifications: Notifications.notifications,
|
notifications: Notifications.notifications,
|
||||||
fetchNotifications: apply(Notifications.fetch, ReactApp.render),
|
fetchNotifications: apply(Notifications.fetchNotifications, ReactApp.render),
|
||||||
|
fetchNotification: apply(Notifications.fetchNotification, ReactApp.render),
|
||||||
markAsRead: apply(Notifications.markAsRead, ReactApp.render),
|
markAsRead: apply(Notifications.markAsRead, ReactApp.render),
|
||||||
markAsUnread: apply(Notifications.markAsUnread, ReactApp.render)
|
markAsUnread: apply(Notifications.markAsUnread, ReactApp.render)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import outdent from 'outdent'
|
import { Link } from 'react-router'
|
||||||
|
|
||||||
|
import NotificationDate from './NotificationDate'
|
||||||
|
import NotificationBody from './NotificationBody'
|
||||||
|
|
||||||
class Notification extends Component {
|
class Notification extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -26,62 +29,6 @@ class Notification extends Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationTextHtml = () => {
|
|
||||||
const { notification } = this.props
|
|
||||||
let map, topic, topic1, topic2
|
|
||||||
let result = `<div class='in-bold'>${notification.actor.name}</div>`
|
|
||||||
|
|
||||||
switch (notification.type) {
|
|
||||||
case 'ACCESS_APPROVED':
|
|
||||||
map = notification.data.map
|
|
||||||
result += outdent`granted your request to edit map
|
|
||||||
<span class='in-bold'>${map.name}</span>`
|
|
||||||
break
|
|
||||||
case 'ACCESS_REQUEST':
|
|
||||||
map = notification.data.map
|
|
||||||
result += outdent`wants permission to map with you on
|
|
||||||
<span class='in-bold'>${map.name}</span>`
|
|
||||||
if (!notification.data.object.answered) {
|
|
||||||
result += '<br /><div class="action">Offer a response</div>'
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'INVITE_TO_EDIT':
|
|
||||||
map = notification.data.map
|
|
||||||
result += outdent`gave you edit access to map
|
|
||||||
<span class='in-bold'>${map.name}</span>`
|
|
||||||
break
|
|
||||||
case 'TOPIC_ADDED_TO_MAP':
|
|
||||||
map = notification.data.map
|
|
||||||
topic = notification.data.topic
|
|
||||||
result += outdent`added topic <span class='in-bold'>${topic.name}</span>
|
|
||||||
to map <span class='in-bold'>${map.name}</span>`
|
|
||||||
break
|
|
||||||
case 'TOPIC_CONNECTED_1':
|
|
||||||
topic1 = notification.data.topic1
|
|
||||||
topic2 = notification.data.topic2
|
|
||||||
result += outdent`connected <span class='in-bold'>${topic1.name}</span>
|
|
||||||
to <span class='in-bold'>${topic2.name}</span>`
|
|
||||||
break
|
|
||||||
case 'TOPIC_CONNECTED_2':
|
|
||||||
topic1 = notification.data.topic1
|
|
||||||
topic2 = notification.data.topic2
|
|
||||||
result += outdent`connected <span class='in-bold'>${topic2.name}</span>
|
|
||||||
to <span class='in-bold'>${topic1.name}</span>`
|
|
||||||
break
|
|
||||||
case 'MESSAGE_FROM_DEVS':
|
|
||||||
result += notification.subject
|
|
||||||
}
|
|
||||||
return {__html: result}
|
|
||||||
}
|
|
||||||
|
|
||||||
getDate = () => {
|
|
||||||
const { notification: {created_at} } = this.props
|
|
||||||
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
|
||||||
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
|
||||||
const created = new Date(created_at)
|
|
||||||
return `${months[created.getMonth()]} ${created.getDate()}`
|
|
||||||
}
|
|
||||||
|
|
||||||
markAsRead = () => {
|
markAsRead = () => {
|
||||||
const { notification, markAsRead } = this.props
|
const { notification, markAsRead } = this.props
|
||||||
markAsRead(notification.id)
|
markAsRead(notification.id)
|
||||||
|
@ -95,19 +42,19 @@ class Notification extends Component {
|
||||||
render = () => {
|
render = () => {
|
||||||
const { notification } = this.props
|
const { notification } = this.props
|
||||||
const classes = `notification ${notification.is_read ? 'read' : 'unread'}`
|
const classes = `notification ${notification.is_read ? 'read' : 'unread'}`
|
||||||
|
const onClick = this.props.onClick || function() {}
|
||||||
|
|
||||||
if (!notification.data.object) {
|
if (!notification.data.object) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return <li className={classes}>
|
return <li className={classes}>
|
||||||
<a href={`/notifications/${notification.id}`}>
|
<Link to={`/notifications/${notification.id}`} onClick={onClick}>
|
||||||
<div className='notification-actor'>
|
<div className='notification-actor'>
|
||||||
<img src={notification.actor.image} />
|
<img src={notification.actor.image} />
|
||||||
</div>
|
</div>
|
||||||
<div className='notification-body'
|
<NotificationBody notification={notification} />
|
||||||
dangerouslySetInnerHTML={this.notificationTextHtml()} />
|
</Link>
|
||||||
</a>
|
|
||||||
<div className='notification-read-unread'>
|
<div className='notification-read-unread'>
|
||||||
{!notification.is_read && <div onClick={this.markAsRead}>
|
{!notification.is_read && <div onClick={this.markAsRead}>
|
||||||
mark read
|
mark read
|
||||||
|
@ -117,7 +64,7 @@ class Notification extends Component {
|
||||||
</div>}
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className='notification-date'>
|
<div className='notification-date'>
|
||||||
{this.getDate()}
|
<NotificationDate date={notification.created_at} />
|
||||||
</div>
|
</div>
|
||||||
<div className='clearfloat'></div>
|
<div className='clearfloat'></div>
|
||||||
</li>
|
</li>
|
||||||
|
|
70
src/components/NotificationBody.js
Normal file
70
src/components/NotificationBody.js
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import outdent from 'outdent'
|
||||||
|
|
||||||
|
import {
|
||||||
|
MAP_ACCESS_REQUEST,
|
||||||
|
MAP_ACCESS_APPROVED,
|
||||||
|
MAP_INVITE_TO_EDIT,
|
||||||
|
TOPIC_ADDED_TO_MAP,
|
||||||
|
TOPIC_CONNECTED_1,
|
||||||
|
TOPIC_CONNECTED_2,
|
||||||
|
MESSAGE_FROM_DEVS
|
||||||
|
} from '../constants'
|
||||||
|
|
||||||
|
class NotificationBody extends Component {
|
||||||
|
notificationTextHtml = () => {
|
||||||
|
const { notification } = this.props
|
||||||
|
let map, topic, topic1, topic2
|
||||||
|
let result = `<div class='in-bold'>${notification.actor.name}</div>`
|
||||||
|
|
||||||
|
switch (notification.type) {
|
||||||
|
case MAP_ACCESS_APPROVED:
|
||||||
|
map = notification.data.map
|
||||||
|
result += outdent`granted your request to edit map
|
||||||
|
<span class='in-bold'>${map.name}</span>`
|
||||||
|
break
|
||||||
|
case MAP_ACCESS_REQUEST:
|
||||||
|
map = notification.data.map
|
||||||
|
result += outdent`wants permission to map with you on
|
||||||
|
<span class='in-bold'>${map.name}</span>`
|
||||||
|
if (!notification.data.object.answered) {
|
||||||
|
result += '<br /><div class="action">Offer a response</div>'
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case MAP_INVITE_TO_EDIT:
|
||||||
|
map = notification.data.map
|
||||||
|
result += outdent`gave you edit access to map
|
||||||
|
<span class='in-bold'>${map.name}</span>`
|
||||||
|
break
|
||||||
|
case TOPIC_ADDED_TO_MAP:
|
||||||
|
map = notification.data.map
|
||||||
|
topic = notification.data.topic
|
||||||
|
result += outdent`added topic <span class='in-bold'>${topic.name}</span>
|
||||||
|
to map <span class='in-bold'>${map.name}</span>`
|
||||||
|
break
|
||||||
|
case TOPIC_CONNECTED_1:
|
||||||
|
topic1 = notification.data.topic1
|
||||||
|
topic2 = notification.data.topic2
|
||||||
|
result += outdent`connected <span class='in-bold'>${topic1.name}</span>
|
||||||
|
to <span class='in-bold'>${topic2.name}</span>`
|
||||||
|
break
|
||||||
|
case TOPIC_CONNECTED_2:
|
||||||
|
topic1 = notification.data.topic1
|
||||||
|
topic2 = notification.data.topic2
|
||||||
|
result += outdent`connected <span class='in-bold'>${topic2.name}</span>
|
||||||
|
to <span class='in-bold'>${topic1.name}</span>`
|
||||||
|
break
|
||||||
|
case MESSAGE_FROM_DEVS:
|
||||||
|
result += notification.subject
|
||||||
|
}
|
||||||
|
return {__html: result}
|
||||||
|
}
|
||||||
|
|
||||||
|
render = () => {
|
||||||
|
return (
|
||||||
|
<div className='notification-body' dangerouslySetInnerHTML={this.notificationTextHtml()} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NotificationBody
|
|
@ -16,10 +16,7 @@ class NotificationBox extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
const { notifications, fetchNotifications } = this.props
|
this.props.fetchNotifications()
|
||||||
if (!notifications) {
|
|
||||||
fetchNotifications()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickOutside = () => {
|
handleClickOutside = () => {
|
||||||
|
@ -28,7 +25,7 @@ class NotificationBox extends Component {
|
||||||
|
|
||||||
hasSomeNotifications = () => {
|
hasSomeNotifications = () => {
|
||||||
const { notifications } = this.props
|
const { notifications } = this.props
|
||||||
return notifications && notifications.length > 0
|
return notifications.length > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
showLoading = () => {
|
showLoading = () => {
|
||||||
|
@ -51,10 +48,11 @@ class NotificationBox extends Component {
|
||||||
n => <Notification notification={n}
|
n => <Notification notification={n}
|
||||||
markAsRead={markAsRead}
|
markAsRead={markAsRead}
|
||||||
markAsUnread={markAsUnread}
|
markAsUnread={markAsUnread}
|
||||||
key={`notification-${n.id}`} />
|
key={`notification-${n.id}`}
|
||||||
|
onClick={() => this.props.toggleNotificationsBox()} />
|
||||||
).concat([
|
).concat([
|
||||||
<li key='notification-see-all'>
|
<li key='notification-see-all'>
|
||||||
<Link to='/notifications' className='notificationsBoxSeeAll'>
|
<Link to='/notifications' className='notificationsBoxSeeAll' onClick={() => this.props.toggleNotificationsBox()}>
|
||||||
See all
|
See all
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
|
|
13
src/components/NotificationDate.js
Normal file
13
src/components/NotificationDate.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
|
||||||
|
class NotificationDate extends Component {
|
||||||
|
render = () => {
|
||||||
|
const { date } = this.props
|
||||||
|
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||||||
|
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||||
|
const created = new Date(date)
|
||||||
|
return <span>{months[created.getMonth()]} {created.getDate()}</span>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NotificationDate
|
7
src/constants.js
Normal file
7
src/constants.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export const MAP_ACCESS_REQUEST = 'ACCESS_REQUEST'
|
||||||
|
export const MAP_ACCESS_APPROVED = 'ACCESS_APPROVED'
|
||||||
|
export const MAP_INVITE_TO_EDIT = 'INVITE_TO_EDIT'
|
||||||
|
export const TOPIC_ADDED_TO_MAP = 'TOPIC_ADDED_TO_MAP'
|
||||||
|
export const TOPIC_CONNECTED_1 = 'TOPIC_CONNECTED_1'
|
||||||
|
export const TOPIC_CONNECTED_2 = 'TOPIC_CONNECTED_2'
|
||||||
|
export const MESSAGE_FROM_DEVS = 'MESSAGE_FROM_DEVS'
|
|
@ -1,13 +1,89 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { Link } from 'react-router'
|
import { Link } from 'react-router'
|
||||||
|
|
||||||
|
import { MAP_ACCESS_REQUEST } from '../../constants'
|
||||||
import NotificationsHeader from './NotificationsHeader'
|
import NotificationsHeader from './NotificationsHeader'
|
||||||
|
import Loading from '../../components/Loading'
|
||||||
|
import NotificationBody from '../../components/NotificationBody'
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
allow / decline access loading states
|
||||||
|
make backend serve HTML for raw body too
|
||||||
|
*/
|
||||||
|
|
||||||
class NotificationPage extends Component {
|
class NotificationPage extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
// the notification id
|
||||||
|
const id = parseInt(this.props.params.id, 10)
|
||||||
|
if (!this.props.notifications.find(n => n.id === id)) {
|
||||||
|
this.props.fetchNotification(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
render = () => {
|
render = () => {
|
||||||
return <NotificationsHeader />
|
const id = parseInt(this.props.params.id, 10)
|
||||||
|
const notification = this.props.notifications.find(n => n.id === id)
|
||||||
|
if (!notification) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div id="yield">
|
||||||
|
<div className="centerContent withPadding back">
|
||||||
|
<Loading />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<NotificationsHeader />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const request = notification.data.object
|
||||||
|
const map = notification.data.map
|
||||||
|
const subject = notification.type === MAP_ACCESS_REQUEST ?
|
||||||
|
(<span><span style={{ fontWeight: 'bold' }} className='requesterName'>{request.user.name}</span> wants to collaborate on map <span style={{fontWeight: 'bold'}}>{ map.name }</span></span>)
|
||||||
|
: notification.subject
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div id="yield">
|
||||||
|
<div className="centerContent withPadding back">
|
||||||
|
<Link to="/notifications">Back to notifications</Link>
|
||||||
|
</div>
|
||||||
|
<div className="centerContent notificationPage">
|
||||||
|
<h2 className="notification-title">
|
||||||
|
<img width="32" height="32" src={notification.actor.image} className='thirty-two-avatar' />
|
||||||
|
{subject}
|
||||||
|
</h2>
|
||||||
|
{notification.type === MAP_ACCESS_REQUEST && <div className="notification-body">
|
||||||
|
<p className="main-text">
|
||||||
|
{request.answered && <span>
|
||||||
|
{request.approved && <span>You already responded to this access request, and allowed access.</span>}
|
||||||
|
{!request.approved && <span>You already responded to this access request, and declined access. If you changed your mind, you can still grant
|
||||||
|
them access by going to the map and adding them as a collaborator.</span>}
|
||||||
|
</span>}
|
||||||
|
{!request.answered && <span>
|
||||||
|
<img src='/images/ellipsis.gif' className='hidden' />
|
||||||
|
<a className="button allow" data-remote="true" rel="nofollow" data-method="post" href={`/maps/${map.id}/approve_access/${request.id}`}>Allow</a>
|
||||||
|
<a className="button decline" data-remote="true" rel="nofollow" data-method="post" href={`/maps/${map.id}/deny_access/${request.id}`}>Decline</a>
|
||||||
|
</span>}
|
||||||
|
</p>
|
||||||
|
<Link to={`/maps/${map.id}`}>Go to map</Link>
|
||||||
|
|
||||||
|
<Link to={`/explore/mapper/${request.user.id}`}>View mapper profile</Link>
|
||||||
|
</div>}
|
||||||
|
{notification.type !== MAP_ACCESS_REQUEST && <NotificationBody notification={notification} />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<NotificationsHeader />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default NotificationPage
|
||||||
|
|
||||||
export default NotificationPage
|
/*
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('.notification-body .button').click(function() {
|
||||||
|
$(this).html('<img src="{ asset_path('ellipsis.gif') }" />')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
*/
|
|
@ -1,78 +1,31 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { Link } from 'react-router'
|
import { Link } from 'react-router'
|
||||||
|
|
||||||
|
import Notification from '../../components/Notification'
|
||||||
|
|
||||||
|
import {
|
||||||
|
MAP_ACCESS_REQUEST,
|
||||||
|
MAP_ACCESS_APPROVED,
|
||||||
|
MAP_INVITE_TO_EDIT
|
||||||
|
} from '../../constants'
|
||||||
import NotificationsHeader from './NotificationsHeader'
|
import NotificationsHeader from './NotificationsHeader'
|
||||||
|
|
||||||
// these come from mailboxer.rb in the api repo
|
// these come from mailboxer.rb in the api repo
|
||||||
const BLACKLIST = ['ACCESS_REQUEST', 'ACCESS_APPROVED', 'INVITE_TO_EDIT']
|
const BLACKLIST = [MAP_ACCESS_REQUEST, MAP_ACCESS_APPROVED, MAP_INVITE_TO_EDIT]
|
||||||
|
|
||||||
/* TODO!!
|
/* TODO!!
|
||||||
pagination
|
pagination
|
||||||
mark read/unread
|
|
||||||
receipts
|
|
||||||
fetchNotifications
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function getNotificationText (notification) {
|
|
||||||
let map, topic, topic1, topic2
|
|
||||||
switch (notification.type) {
|
|
||||||
case 'ACCESS_APPROVED':
|
|
||||||
map = notification.data.map
|
|
||||||
return (
|
|
||||||
<span>granted your request to edit map <span className="in-bold">{map.name}</span></span>
|
|
||||||
)
|
|
||||||
case 'ACCESS_REQUEST':
|
|
||||||
map = notification.data.map
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
wants permission to map with you on <span className="in-bold">{map.name}</span>
|
|
||||||
{!notification.data.object.answered && <span> <div className="action">Offer a response</div></span>}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
case 'INVITE_TO_EDIT':
|
|
||||||
map = notification.data.map
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
gave you edit access to map <span className="in-bold">{map.name}</span>
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
case 'TOPIC_ADDED_TO_MAP':
|
|
||||||
topic = notification.data.topic
|
|
||||||
map = notification.data.map
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
added topic <span className="in-bold">{topic.name}</span> to map <span className="in-bold">{map.name}</span>
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
case 'TOPIC_CONNECTED_1':
|
|
||||||
topic1 = notification.data.topic1
|
|
||||||
topic2 = notification.data.topic2
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
connected <span className="in-bold">{topic1.name}</span> to <span className="in-bold">{topic2.name}</span>
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
case 'TOPIC_CONNECTED_2':
|
|
||||||
topic1 = notification.data.topic1
|
|
||||||
topic2 = notification.data.topic2
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
connected <span className="in-bold">{topic2.name}</span> to <span className="in-bold">{topic1.name}</span>
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
case 'MESSAGE_FROM_DEVS':
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
{notification.subject}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
default:
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Notifications extends Component {
|
class Notifications extends Component {
|
||||||
|
componentDidMount = () => {
|
||||||
|
this.props.fetchNotifications()
|
||||||
|
}
|
||||||
|
|
||||||
render = () => {
|
render = () => {
|
||||||
|
const { 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)))
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -83,11 +36,12 @@ class Notifications extends Component {
|
||||||
</header>
|
</header>
|
||||||
<ul className="notifications">
|
<ul className="notifications">
|
||||||
{notifications.map(n => {
|
{notifications.map(n => {
|
||||||
// TODO: const receipt = this.props.receipts.find(n => n.notification_id === notification.id)
|
return (
|
||||||
const receipt = {
|
<Notification key={`notification-${n.id}`}
|
||||||
is_read: false
|
notification={n}
|
||||||
}
|
markAsRead={markAsRead}
|
||||||
return <Notification key={n.id} notification={n} receipt={receipt} />
|
markAsUnread={markAsUnread} />
|
||||||
|
)
|
||||||
})}
|
})}
|
||||||
{notifications.length === 0 && <div className="emptyInbox">
|
{notifications.length === 0 && <div className="emptyInbox">
|
||||||
You have no notifications. More time for dancing.
|
You have no notifications. More time for dancing.
|
||||||
|
@ -110,30 +64,4 @@ class Paginate extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Notification extends Component {
|
|
||||||
render = () => {
|
|
||||||
const { notification, receipt } = this.props
|
|
||||||
return (
|
|
||||||
<li className={`notification ${receipt.is_read ? 'read' : 'unread' }`} id={`notification-${ notification.id }`}>
|
|
||||||
<Link to={`/notifications/${notification.id}`}>
|
|
||||||
<div className="notification-actor">
|
|
||||||
<img src={notification.actor.image} />
|
|
||||||
</div>
|
|
||||||
<div className="notification-body">
|
|
||||||
<div className="in-bold">{notification.actor.name}</div>
|
|
||||||
{getNotificationText(notification)}
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
<div className="notification-read-unread">
|
|
||||||
<a data-remote="true" rel="nofollow" data-method="put" href={`/notifications/${notification.id}/mark_${receipt.is_read ? 'un' : ''}read`}>mark as {receipt.is_read ? 'un' : ''}read</a>
|
|
||||||
</div>
|
|
||||||
<div className="notification-date">
|
|
||||||
{notification.created_at}
|
|
||||||
</div>
|
|
||||||
<div className="clearfloat"></div>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Notifications
|
export default Notifications
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
import React, { Component } from react
|
|
||||||
|
|
||||||
class MyComponent extends Component {
|
|
||||||
render = () => {
|
|
||||||
return (
|
|
||||||
<div id="yield">
|
|
||||||
<div className="centerContent withPadding back">
|
|
||||||
{ link_to 'Back to notifications', notifications_path }
|
|
||||||
</div>
|
|
||||||
<div className="centerContent notificationPage">
|
|
||||||
<h2 className="notification-title">
|
|
||||||
{ case @notification.notification_code
|
|
||||||
when MAP_ACCESS_REQUEST
|
|
||||||
request = @notification.notified_object
|
|
||||||
map = request.map }
|
|
||||||
{ image_tag @notification.sender.image(:thirtytwo), className: 'thirty-two-avatar' } <span style='font-weight:bold;' className='requesterName'>{ request.user.name }</span> wants to collaborate on map <span style='font-weight:bold;'>{ map.name }</span>
|
|
||||||
{ else }
|
|
||||||
{ @notification.subject }
|
|
||||||
{ end }
|
|
||||||
</h2>
|
|
||||||
{ case @notification.notification_code
|
|
||||||
when MAP_ACCESS_REQUEST }
|
|
||||||
<div className="notification-body">
|
|
||||||
<p className="main-text">
|
|
||||||
{ if false && request.answered }
|
|
||||||
{ if request.approved }
|
|
||||||
You already responded to this access request, and allowed access.
|
|
||||||
{ elsif !request.approved }
|
|
||||||
You already responded to this access request, and declined access. If you changed your mind, you can still grant
|
|
||||||
them access by going to the map and adding them as a collaborator.
|
|
||||||
{ end }
|
|
||||||
{ else }
|
|
||||||
{ image_tag asset_path('ellipsis.gif'), className: 'hidden' }
|
|
||||||
{ link_to 'Allow', approve_access_post_map_path(id: map.id, request_id: request.id), remote: true, method: :post, className: 'button allow' }
|
|
||||||
{ link_to 'Decline', deny_access_post_map_path(id: map.id, request_id: request.id), remote: true, method: :post, className: 'button decline' }
|
|
||||||
<script>
|
|
||||||
$(document).ready(function() {
|
|
||||||
$('.notification-body .button').click(function() {
|
|
||||||
$(this).html('<img src="{ asset_path('ellipsis.gif') }" />')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
{ end }
|
|
||||||
</p>
|
|
||||||
{ link_to 'Go to map', map_url(map) }
|
|
||||||
{ link_to 'View mapper profile', explore_path(id: request.user.id) }
|
|
||||||
</div>
|
|
||||||
{ else }
|
|
||||||
<div className="notification-body">
|
|
||||||
{ raw @notification.body }
|
|
||||||
</div>
|
|
||||||
{ end }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MyComponent
|
|
Loading…
Reference in a new issue