improve styling, fix index notifs page

This commit is contained in:
Connor Turland 2017-09-25 15:21:04 -04:00
parent fc8ac6eef1
commit 277644f59d
10 changed files with 121 additions and 22 deletions

View file

@ -1,4 +1,6 @@
$notifications-border-color: #DDDDDD;
$unread_notifications_dot_size: 8px; $unread_notifications_dot_size: 8px;
.unread-notifications-dot { .unread-notifications-dot {
width: $unread_notifications_dot_size; width: $unread_notifications_dot_size;
height: $unread_notifications_dot_size; height: $unread_notifications_dot_size;
@ -22,6 +24,7 @@ $unread_notifications_dot_size: 8px;
right: 0; right: 0;
top: 50px; top: 50px;
box-shadow: 0 3px 6px rgba(0,0,0,0.16); box-shadow: 0 3px 6px rgba(0,0,0,0.16);
border: 1px solid $notifications-border-color;
.notificationsBoxTriangle { .notificationsBoxTriangle {
min-width: 0 !important; min-width: 0 !important;
@ -31,9 +34,9 @@ $unread_notifications_dot_size: 8px;
width: 20px !important; width: 20px !important;
height: 20px !important; height: 20px !important;
margin-left: -10px; margin-left: -10px;
top: -10px; top: -11px;
border-top: 1px solid rgba(49, 72, 67, 0.11) !important; border-left: 1px solid $notifications-border-color;
border-left: 1px solid rgba(49, 72, 67, 0.11) !important; border-top: 1px solid $notifications-border-color;
border-bottom: 0 !important; border-bottom: 0 !important;
border-right: 0 !important; border-right: 0 !important;
background-color: #fff; background-color: #fff;
@ -42,6 +45,11 @@ $unread_notifications_dot_size: 8px;
-ms-transform: rotate(45deg); -ms-transform: rotate(45deg);
} }
ul.notifications {
max-height: 500px;
overflow-y: auto;
}
.notificationsBoxSeeAll { .notificationsBoxSeeAll {
display: block; display: block;
width: 100%; width: 100%;
@ -51,6 +59,14 @@ $unread_notifications_dot_size: 8px;
color: #4fb5c0; color: #4fb5c0;
border-top: 1px solid rgba(0, 0, 0, 0.1); border-top: 1px solid rgba(0, 0, 0, 0.1);
} }
.notification {
font-size: 13px;
.notification-body {
border-bottom: 1px solid $notifications-border-color;
}
}
} }
} }
@ -121,11 +137,18 @@ $unread_notifications_dot_size: 8px;
ul.notifications { ul.notifications {
list-style: none; list-style: none;
li:last-child {
.notification-body {
border-bottom: none !important;
}
}
} }
.notification { .notification {
padding: 10px; padding: 10px 10px 0 10px;
position: relative; position: relative;
font-family: 'din-regular', Sans-Serif;
&:hover { &:hover {
background: #F6F6F6; background: #F6F6F6;
@ -157,9 +180,9 @@ ul.notifications {
} }
.notification-body { .notification-body {
font-family: 'din-regular', Sans-Serif;
margin-left: 50px; margin-left: 50px;
line-height: 20px; line-height: 20px;
padding-bottom: 10px;
.in-bold { .in-bold {
font-family: 'din-medium', Sans-Serif; font-family: 'din-medium', Sans-Serif;
@ -180,8 +203,6 @@ ul.notifications {
top: 50%; top: 50%;
right: 10px; right: 10px;
color: #607d8b; color: #607d8b;
font-size: 13px;
line-height: 13px;
margin-top: -6px; margin-top: -6px;
} }
@ -190,11 +211,12 @@ ul.notifications {
float: left; float: left;
width: 15%; width: 15%;
div { a, div {
position: absolute; position: absolute;
top: 50%; top: 50%;
margin-top: -10px; margin-top: -10px;
text-align: center; text-align: center;
cursor: pointer;
} }
} }

View file

@ -43,6 +43,7 @@ class NotificationsController < ApplicationController
def mark_read def mark_read
@receipt.update(is_read: true) @receipt.update(is_read: true)
respond_to do |format| respond_to do |format|
format.js
format.json do format.json do
render json: NotificationDecorator.decorate(@notification, @receipt) render json: NotificationDecorator.decorate(@notification, @receipt)
end end
@ -52,6 +53,7 @@ class NotificationsController < ApplicationController
def mark_unread def mark_unread
@receipt.update(is_read: false) @receipt.update(is_read: false)
respond_to do |format| respond_to do |format|
format.js
format.json do format.json do
render json: NotificationDecorator.decorate(@notification, @receipt) render json: NotificationDecorator.decorate(@notification, @receipt)
end end

View file

@ -38,7 +38,7 @@ class NotificationDecorator
id: topic1&.id, id: topic1&.id,
name: topic1&.name name: topic1&.name
} }
resul[:data][:topic2] = { result[:data][:topic2] = {
id: topic2&.id, id: topic2&.id,
name: topic2&.name name: topic2&.name
} }

View file

@ -8,7 +8,7 @@
</header> </header>
<ul class="notifications"> <ul class="notifications">
<% blacklist = [MAP_ACCESS_REQUEST, MAP_ACCESS_APPROVED, MAP_INVITE_TO_EDIT] %> <% blacklist = [MAP_ACCESS_REQUEST, MAP_ACCESS_APPROVED, MAP_INVITE_TO_EDIT] %>
<% notifications = @notifications.to_a.delete_if{|n| blacklist.include?(n.notification_code) && (n.notified_object.nil? || n.notified_object.map.nil?) }%> <% notifications = @notifications.to_a.delete_if{|n| blacklist.include?(n.notification_code) && (n.notified_object.nil? || n.notified_object.map.nil?) }%>
<% notifications.each do |notification| %> <% notifications.each do |notification| %>
<% receipt = @receipts.find_by(notification_id: notification.id) %> <% receipt = @receipts.find_by(notification_id: notification.id) %>
<li class="notification <%= receipt.is_read? ? 'read' : 'unread' %>" id="notification-<%= notification.id %>"> <li class="notification <%= receipt.is_read? ? 'read' : 'unread' %>" id="notification-<%= notification.id %>">

View file

@ -0,0 +1,7 @@
$('#notification-<%= @notification.id %> .notification-read-unread > a')
.text('mark as unread')
.attr('href', '<%= mark_unread_notification_path(@notification.id) %>')
$('#notification-<%= @notification.id %>')
.removeClass('unread')
.addClass('read')
Metamaps.GlobalUI.Notifications.decrementUnread(Metamaps.GlobalUI.ReactApp.render)

View file

@ -0,0 +1,7 @@
$('#notification-<%= @notification.id %> .notification-read-unread > a')
.text('mark as read')
.attr('href', '<%= mark_read_notification_path(@notification.id) %>')
$('#notification-<%= @notification.id %>')
.removeClass('read')
.addClass('unread')
Metamaps.GlobalUI.Notifications.incrementUnread(Metamaps.GlobalUI.ReactApp.render)

View file

@ -15,14 +15,22 @@ const Notifications = {
} }
}) })
}, },
incrementUnread: (render) => {
Notifications.unreadNotificationsCount++
render()
},
decrementUnread: (render) => {
Notifications.unreadNotificationsCount--
render()
},
markAsRead: (render, id) => { markAsRead: (render, id) => {
const n = Notifications.notifications.find(n => n.id === id) const n = Notifications.notifications.find(n => n.id === id)
$.ajax({ $.ajax({
url: `/notifications/${id}/mark_read`, url: `/notifications/${id}/mark_read.json`,
method: 'PUT', method: 'PUT',
success: function(r) { success: function(r) {
if (n) { if (n) {
Notifications.unreadNotificationsCount--
n.is_read = true n.is_read = true
render() render()
} }
@ -35,7 +43,7 @@ const Notifications = {
markAsUnread: (render, id) => { markAsUnread: (render, id) => {
const n = Notifications.notifications.find(n => n.id === id) const n = Notifications.notifications.find(n => n.id === id)
$.ajax({ $.ajax({
url: `/notifications/${id}/mark_unread`, url: `/notifications/${id}/mark_unread.json`,
method: 'PUT', method: 'PUT',
success: function() { success: function() {
if (n) { if (n) {

View file

@ -18,6 +18,7 @@ const GlobalUI = {
init: function(serverData) { init: function(serverData) {
const self = GlobalUI const self = GlobalUI
self.Notifications.init(serverData)
self.ReactApp.init(serverData, self.openLightbox) self.ReactApp.init(serverData, self.openLightbox)
self.CreateMap.init(serverData) self.CreateMap.init(serverData)
self.ImportDialog.init(serverData, self.openLightbox, self.closeLightbox) self.ImportDialog.init(serverData, self.openLightbox, self.closeLightbox)

View file

@ -31,7 +31,7 @@ class NotificationBox extends Component {
<div className='notificationsBoxTriangle' /> <div className='notificationsBoxTriangle' />
<ul className='notifications'> <ul className='notifications'>
{!notifications && <li>loading...</li>} {!notifications && <li>loading...</li>}
{notifications && notifications.map(n => { {notifications && notifications.slice(0, 10).map(n => {
return <Notification notification={n} return <Notification notification={n}
markAsRead={markAsRead} markAsRead={markAsRead}
markAsUnread={markAsUnread} markAsUnread={markAsUnread}

View file

@ -1,5 +1,6 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import outdent from 'outdent'
class Notification extends Component { class Notification extends Component {
@ -26,10 +27,58 @@ 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 = () => { getDate = () => {
const { notification: {created_at} } = this.props const { notification: {created_at} } = this.props
const months = ['Jan','Feb','Mar','Apr','May','Jun', const months = ['Jan','Feb','Mar','Apr','May','Jun',
'Jul','Aug','Sep','Oct','Nov','Dec'] 'Jul','Aug','Sep','Oct','Nov','Dec']
const created = new Date(created_at) const created = new Date(created_at)
return `${months[created.getMonth()]} ${created.getDate()}` return `${months[created.getMonth()]} ${created.getDate()}`
} }
@ -47,17 +96,20 @@ 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'}`
if (!notification.data.object) {
return null
}
return <li className={classes}> return <li className={classes}>
<a href={`/notifications/${notification.id}`}> <a href={`/notifications/${notification.id}`}>
<div className='notification-actor'> <div className='notification-actor'>
<img src={notification.actor.image} /> <img src={notification.actor.image} />
</div> </div>
<div className="notification-body"> <div className='notification-body'
<div className="in-bold">{notification.actor.name}</div> dangerouslySetInnerHTML={this.notificationTextHtml()} />
Other content
</div>
</a> </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
</div>} </div>}
@ -65,10 +117,10 @@ class Notification extends Component {
mark unread mark unread
</div>} </div>}
</div> </div>
<div className="notification-date"> <div className='notification-date'>
{this.getDate()} {this.getDate()}
</div> </div>
<div className="clearfloat"></div> <div className='clearfloat'></div>
</li> </li>
} }
} }