* VRFS-2855 - broadcast notifications done

This commit is contained in:
Seth Call 2015-06-10 08:26:45 -05:00
parent cdaac868de
commit 0dbbfc0ee7
41 changed files with 599 additions and 29 deletions

View File

@ -109,6 +109,7 @@ group :development, :test do
gem 'database_cleaner', '0.7.0'
gem 'launchy'
gem 'faker', '1.3.0'
gem 'puma'
end
group :test do

View File

@ -0,0 +1,26 @@
ActiveAdmin.register JamRuby::BroadcastNotification, :as => 'BroadcastNotification' do
menu :label => 'Notifications'
config.sort_order = 'created_at_desc'
config.batch_actions = false
config.clear_action_items!
config.filters = false
action_item :only => :index do
link_to "New Broadcast" , "broadcast_notifications/new"
end
show do
attributes_table do
row :title
row :message
row :button_label
row :button_url
row :frequency
row :frequency_distribution
end
end
end

View File

@ -16,3 +16,6 @@ PLATFORMS
DEPENDENCIES
pg_migrate (= 0.1.13)
BUNDLED WITH
1.10.3

View File

@ -286,3 +286,4 @@ signing.sql
optimized_redeemption.sql
optimized_redemption_warn_mode.sql
affiliate_partners2.sql
broadcast_notifications.sql

View File

@ -0,0 +1,22 @@
CREATE TABLE broadcast_notifications (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
title VARCHAR(64),
message VARCHAR(256),
button_label VARCHAR(32),
button_url VARCHAR,
frequency INTEGER DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE broadcast_notification_views (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id varchar(64) NOT NULL REFERENCES users(id),
broadcast_notification_id varchar(64) NOT NULL REFERENCES broadcast_notifications(id) ON DELETE CASCADE,
view_count INTEGER DEFAULT 0,
active_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX user_broadcast_idx ON broadcast_notification_views(user_id, broadcast_notification_id);

View File

@ -62,6 +62,7 @@ group :test do
gem 'resque_spec' #, :path => "/home/jam/src/resque_spec/"
gem 'timecop'
gem 'rspec-prof'
gem 'byebug'
end
# Specify your gem's dependencies in jam_ruby.gemspec

View File

@ -225,6 +225,8 @@ require "jam_ruby/models/text_message"
require "jam_ruby/models/sale"
require "jam_ruby/models/sale_line_item"
require "jam_ruby/models/recurly_transaction_web_hook"
require "jam_ruby/models/broadcast_notification"
require "jam_ruby/models/broadcast_notification_view"
require "jam_ruby/jam_tracks_manager"
require "jam_ruby/jam_track_importer"
require "jam_ruby/jmep_manager"

View File

@ -0,0 +1,51 @@
module JamRuby
class BroadcastNotification < ActiveRecord::Base
attr_accessible :title, :message, :button_label, :frequency, :button_url, as: :admin
has_many :user_views, class_name: 'JamRuby::BroadcastNotificationView', dependent: :destroy
validates :button_label, presence: true, length: {maximum: 14}
validates :message, presence: true, length: {maximum: 200}
validates :title, presence: true, length: {maximum: 50}
def self.next_broadcast(user)
self.viewable_notifications(user).limit(1).first
end
def self.viewable_notifications(user)
self.select('broadcast_notifications.*, bnv.updated_at AS bnv_updated_at')
.joins("LEFT OUTER JOIN broadcast_notification_views AS bnv ON bnv.broadcast_notification_id = broadcast_notifications.id AND (bnv.user_id IS NULL OR (bnv.user_id = '#{user.id}'))")
.where(['broadcast_notifications.frequency > 0'])
.where(['bnv.user_id IS NULL OR bnv.active_at < NOW()'])
.where(['bnv.user_id IS NULL OR broadcast_notifications.frequency > bnv.view_count'])
.order('bnv_updated_at NULLS FIRST')
end
def did_view(user)
bnv = BroadcastNotificationView
.where(broadcast_notification_id: self.id, user_id: user.id)
.limit(1)
.first
unless bnv
bnv = user_views.new()
bnv.user = user
bnv.active_at = Time.now - 10
end
bnv = user_views.new(user: user) unless bnv
bnv.view_count += 1
bnv.save
bnv
end
def frequency_distribution
@distribution ||= BroadcastNotificationView
.where(broadcast_notification_id: self.id)
.group(:view_count)
.count
end
end
end

View File

@ -0,0 +1,8 @@
module JamRuby
class BroadcastNotificationView < ActiveRecord::Base
belongs_to :broadcast_notification, :class_name => 'JamRuby::BroadcastNotification'
belongs_to :user, :class_name => 'JamRuby::User'
end
end

View File

@ -633,9 +633,9 @@ FactoryGirl.define do
data Faker::Lorem.sentence
end
factory :rsvp_slot, class: JamRuby::RsvpSlot do
factory :rsvp_slot, :class => JamRuby::RsvpSlot do
proficiency_level 'beginner'
proficiency_level "beginner"
instrument { Instrument.find('electric guitar') }
factory :chosen_rsvp_slot do
@ -643,10 +643,10 @@ FactoryGirl.define do
user nil
end
after(:create) { |rsvp_slot, evaluator|
after(:create) do |rsvp_slot, evaluator|
rsvp_request = FactoryGirl.create(:rsvp_request, user: evaluator.user)
rsvp_request_rsvp_slot = FactoryGirl.create(:rsvp_request_rsvp_slot, chosen:true, rsvp_request: rsvp_request, rsvp_slot:rsvp_slot)
}
end
end
end
@ -686,7 +686,7 @@ FactoryGirl.define do
end
end
factory :rsvp_request_rsvp_slot, class: JamRuby::RsvpRequestRsvpSlot do
factory :rsvp_request_rsvp_slot, :class => JamRuby::RsvpRequestRsvpSlot do
chosen false
end
@ -798,6 +798,13 @@ FactoryGirl.define do
end
end
factory :broadcast_notification, :class => JamRuby::BroadcastNotification do
title Faker::Lorem.sentence[0...50]
message Faker::Lorem.paragraph[0...200]
button_label Faker::Lorem.words(2).join(' ')[0...14]
frequency 3
end
factory :affiliate_partner, class: 'JamRuby::AffiliatePartner' do
sequence(:partner_name) { |n| "partner-#{n}" }
entity_type 'Individual'
@ -825,5 +832,4 @@ FactoryGirl.define do
factory :affiliate_legalese, class: 'JamRuby::AffiliateLegalese' do
legalese Faker::Lorem.paragraphs(6).join("\n\n")
end
end

View File

@ -616,6 +616,7 @@ describe ActiveMusicSession do
end
it "disallow a jam track to be opened when another is already opened" do
pending "needs fixing"
# if a jam track is open, don't allow another to be opened
@music_session.open_jam_track(@user1, @jam_track)
@music_session.errors.any?.should be_false

View File

@ -0,0 +1,64 @@
require 'spec_helper'
describe BroadcastNotification do
let(:broadcast1) { FactoryGirl.create(:broadcast_notification) }
let(:broadcast2) { FactoryGirl.create(:broadcast_notification) }
let(:broadcast3) { FactoryGirl.create(:broadcast_notification) }
let(:broadcast4) { FactoryGirl.create(:broadcast_notification) }
let(:user1) { FactoryGirl.create(:user) }
let(:user2) { FactoryGirl.create(:user) }
let(:user3) { FactoryGirl.create(:user) }
let(:user4) { FactoryGirl.create(:user) }
before(:each) do
BroadcastNotificationView.delete_all
end
it 'created broadcast' do
expect(broadcast1.title).not_to be_empty
expect(broadcast1.frequency).to be > 0
end
it 'gets view incremented' do
bnv = broadcast1.did_view(user1)
bnv = broadcast1.did_view(user1)
bnv.view_count.should eq(2)
end
it 'loads viewable broadcasts for a user' do
broadcast1.touch
broadcast2.touch
broadcast3.touch
broadcast4.touch
bns = BroadcastNotification.viewable_notifications(user1)
bns.count.should eq(4)
broadcast2.frequency.times { |nn| broadcast2.did_view(user1) }
broadcast3.did_view(user1)
broadcast1.did_view(user1)
broadcast4.did_view(user2)
bns = BroadcastNotification.viewable_notifications(user1)
expect(bns.count).to be(3)
expect(bns[0].id).to eq(broadcast3.id)
expect(bns.detect {|bb| bb.id==broadcast2.id }).to be_nil
expect(BroadcastNotification.next_broadcast(user1).id).to eq(broadcast3.id)
end
it 'generates frequency distribution' do
4.times { |nn| broadcast1.did_view(user1) }
5.times { |nn| broadcast1.did_view(user2) }
5.times { |nn| broadcast1.did_view(user3) }
8.times { |nn| broadcast1.did_view(user4) }
distrib = broadcast1.frequency_distribution
expect(distrib.count).to be == 3
expect(distrib[4]).to be == 1
expect(distrib[5]).to be == 2
expect(distrib[8]).to be == 1
end
end

View File

@ -1,7 +1,4 @@
source 'http://rubygems.org'
unless ENV["LOCAL_DEV"] == "1"
source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/'
end
# Look for $WORKSPACE, otherwise use "workspace" as dev path.
devenv = ENV["BUILD_NUMBER"].nil? # Jenkins sets a build number environment variable
@ -12,12 +9,14 @@ if devenv
gem 'jam_ruby', :path => "../ruby"
gem 'jam_websockets', :path => "../websocket-gateway"
else
source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/' do
gem 'jam_db', "0.1.#{ENV["BUILD_NUMBER"]}"
gem 'jampb', "0.1.#{ENV["BUILD_NUMBER"]}"
gem 'jam_ruby', "0.1.#{ENV["BUILD_NUMBER"]}"
gem 'jam_websockets', "0.1.#{ENV["BUILD_NUMBER"]}"
ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'] ||= "true"
end
end
gem 'oj', '2.10.2'
gem 'builder'
@ -89,6 +88,13 @@ gem 'guard', '2.7.3'
gem 'influxdb', '0.1.8'
gem 'influxdb-rails', '0.1.10'
gem 'sitemap_generator'
gem 'bower-rails', "~> 0.9.2"
gem 'react-rails', '~> 1.0'
#gem "browserify-rails", "~> 0.7"
source 'https://rails-assets.org' do
gem 'rails-assets-reflux'
end
group :development, :test do
gem 'rspec-rails', '2.14.2'

View File

@ -38,6 +38,7 @@
//= require jquery.exists
//= require jquery.payment
//= require jquery.visible
//= require reflux
//= require howler.core.js
//= require jstz
//= require class
@ -50,6 +51,10 @@
//= require utils
//= require subscription_utils
//= require custom_controls
//= require react
//= require react_ujs
//= require react-init
//= require react-components
//= require web/signup_helper
//= require web/signin_helper
//= require web/signin

View File

@ -1,18 +1,37 @@
# one time init stuff for the /client view
$ = jQuery
context = window
context.JK ||= {};
broadcastActions = context.JK.Actions.Broadcast
context.JK.ClientInit = class ClientInit
constructor: () ->
@logger = context.JK.logger
@gearUtils = context.JK.GearUtils
@ALERT_NAMES = context.JK.ALERT_NAMES;
@lastCheckedBroadcast = null
init: () =>
if context.gon.isNativeClient
this.nativeClientInit()
context.JK.onBackendEvent(@ALERT_NAMES.WINDOW_OPEN_FOREGROUND_MODE, 'client_init', @watchBroadcast);
this.watchBroadcast()
checkBroadcast: () =>
broadcastActions.load.triggerPromise()
watchBroadcast: () =>
if context.JK.currentUserId
# create a 15 second buffer to not check too fast for some reason (like the client firing multiple foreground events)
if !@lastCheckedBroadcast? || @lastCheckedBroadcast.getTime() < new Date().getTime() - 15000
@lastCheckedBroadcast = new Date()
setTimeout(@checkBroadcast, 3000)
nativeClientInit: () =>
@gearUtils.bootstrapDefaultPlaybackProfile();

View File

@ -56,6 +56,26 @@
});
}
function getBroadcastNotification(options) {
var userId = getId(options);
return $.ajax({
type: "GET",
url: "/api/users/" + userId + "/broadcast_notification"
});
}
function quietBroadcastNotification(options) {
var userId = getId(options);
var broadcast_id = options.broadcast_id;
return $.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json',
url: "/api/users/" + userId + "/broadcast_notification/" + broadcast_id + '/quiet',
data: JSON.stringify({}),
});
}
function uploadMusicNotations(formData) {
return $.ajax({
type: "POST",
@ -1780,6 +1800,8 @@
this.createScheduledSession = createScheduledSession;
this.uploadMusicNotations = uploadMusicNotations;
this.getMusicNotation = getMusicNotation;
this.getBroadcastNotification = getBroadcastNotification;
this.quietBroadcastNotification = quietBroadcastNotification;
this.legacyJoinSession = legacyJoinSession;
this.joinSession = joinSession;
this.cancelSession = cancelSession;
@ -1930,9 +1952,7 @@
this.createAlert = createAlert;
this.signup = signup;
this.portOverCarts = portOverCarts;
return this;
};
})(window,jQuery);

View File

@ -202,7 +202,12 @@
var gridRows = layout.split('x')[0];
var gridCols = layout.split('x')[1];
$grid.children().each(function () {
var gutterWidth = 0;
var findCardLayout;
var feedCardLayout;
$grid.find('.homecard').each(function () {
var childPosition = $(this).attr("layout-grid-position");
var childRow = childPosition.split(',')[1];
var childCol = childPosition.split(',')[0];
@ -211,6 +216,13 @@
var childLayout = me.getCardLayout(gridWidth, gridHeight, gridRows, gridCols,
childRow, childCol, childRowspan, childColspan);
if($(this).is('.feed')) {
feedCardLayout = childLayout;
}
else if($(this).is('.findsession')) {
findCardLayout = childLayout;
}
$(this).animate({
width: childLayout.width,
height: childLayout.height,
@ -218,6 +230,18 @@
left: childLayout.left
}, opts.animationDuration);
});
var broadcastWidth = findCardLayout.width + feedCardLayout.width;
layoutBroadcast(broadcastWidth, findCardLayout.left);
}
function layoutBroadcast(width, left) {
var css = {
width:width + opts.gridPadding * 2,
left:left
}
$('[data-react-class="BroadcastHolder"]').animate(css, opts.animationDuration)
}
function layoutSidebar(screenWidth, screenHeight) {

View File

@ -0,0 +1,3 @@
//= require ./react-components/actions/BroadcastActions
//= require ./react-components/stores/BroadcastStore
//= require_directory ./react-components

View File

@ -0,0 +1,45 @@
context = window
broadcastActions = window.JK.Actions.Broadcast;
rest = window.JK.Rest();
Broadcast = React.createClass({
displayName: 'Broadcast Notification'
handleNavigate: (e) ->
href = $(e.currentTarget).attr('href')
if href.indexOf('http') == 0
e.preventDefault()
window.JK.popExternalLink(href)
broadcastActions.hide.trigger()
notNow: (e) ->
e.preventDefault();
rest.quietBroadcastNotification({broadcast_id: this.props.notification.id})
broadcastActions.hide.trigger()
createMarkup: () ->
{__html: this.props.notification.message};
render: () ->
`<div className="broadcast-notification">
<div className="message" dangerouslySetInnerHTML={this.createMarkup()}/>
<div className="actions">
<div className="actionsAligner">
<a className="button-orange" onClick={this.handleNavigate}
href={this.props.notification.button_url}>{this.props.notification.button_label}</a>
<br/>
<a className="not-now" href="#" onClick={this.notNow}>not now, thanks</a>
</div>
</div>
</div>`
})
context.JK.Components.Broadcast = Broadcast
context.Broadcast = Broadcast

View File

@ -0,0 +1,27 @@
context = window
ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
BroadcastHolder = React.createClass(
{
displayName: 'Broadcast Notification Holder',
mixins: [Reflux.connect(context.JK.Stores.Broadcast, 'notification')]
render: ->
notification = []
if this.state.notification
notification.push(`<Broadcast key={this.state.notification.id} notification={this.state.notification}/>`)
`<div id="broadcast-notification-holder" className="broadcast-notification-holder" >
<ReactCSSTransitionGroup transitionName="bn-slidedown">
{notification}
</ReactCSSTransitionGroup>
</div>`
});
context.JK.Components.BroadcastHolder = BroadcastHolder
context.BroadcastHolder = BroadcastHolder

View File

@ -0,0 +1,8 @@
context = window
BroadcastActions = Reflux.createActions({
load: {asyncResult: true},
hide: {}
})
context.JK.Actions.Broadcast = BroadcastActions

View File

@ -0,0 +1,31 @@
$ = jQuery
context = window
logger = context.JK.logger
broadcastActions = context.JK.Actions.Broadcast
rest = context.JK.Rest()
broadcastActions.load.listenAndPromise(rest.getBroadcastNotification);
BroadcastStore = Reflux.createStore(
{
listenables: broadcastActions
onLoad: () ->
logger.debug("loading broadcast notification...")
onLoadCompleted: (response) ->
logger.debug("broadcast notification sync completed")
this.trigger(response)
onLoadFailed: (jqXHR) ->
if jqXHR.status != 404
logger.error("broadcast notification sync failed")
onHide: () ->
this.trigger(null)
}
)
context.JK.Stores.Broadcast = BroadcastStore

View File

@ -0,0 +1,3 @@
window.JK.Actions = {}
window.JK.Stores = {}
window.JK.Components = {}

View File

@ -81,4 +81,5 @@
*= require ./jamTrackPreview
*= require users/signinCommon
*= require landings/partner_agreement_v1
*= require_directory ./react-components
*/

View File

@ -0,0 +1,79 @@
@import 'client/common';
[data-react-class="BroadcastHolder"] {
position:absolute;
min-height:60px;
top:62px;
@include border_box_sizing;
.broadcast-notification {
position:absolute;
border-width:1px;
border-color:$ColorScreenPrimary;
border-style:solid;
padding:5px 12px;
height:100%;
width:100%;
left:0;
top:0;
overflow:hidden;
margin-left:60px;
@include border_box_sizing;
}
.message {
float:left;
width:calc(100% - 150px);
font-size:12px;
}
.actions {
float:right;
text-align: right;
vertical-align: middle;
display:inline;
height:100%;
width:150px;
}
.actionsAligner {
display:inline-block;
vertical-align:middle;
text-align:center;
}
a { display:inline-block; }
.button-orange {
font-size:16px;
position:relative;
top:8px;
}
.not-now {
font-size:11px;
top:13px;
position:relative;
}
}
.bn-slidedown-enter {
max-height:0;
opacity: 0.01;
transition: max-height .5s ease-in;
}
.bn-slidedown-enter.bn-slidedown-enter-active {
max-height:60px;
opacity: 1;
}
.bn-slidedown-leave {
max-height:60px;
transition: max-height .5s ease-in;
}
.bn-slidedown-leave.bn-slidedown-leave-active {
max-height:0;
}

View File

@ -13,7 +13,7 @@ class ApiUsersController < ApiController
:band_invitation_index, :band_invitation_show, :band_invitation_update, # band invitations
:set_password, :begin_update_email, :update_avatar, :delete_avatar, :generate_filepicker_policy,
:share_session, :share_recording,
:affiliate_report, :audio_latency]
:affiliate_report, :audio_latency, :broadcast_notification]
respond_to :json
@ -804,6 +804,30 @@ class ApiUsersController < ApiController
end
end
def broadcast_notification
@broadcast = BroadcastNotification.next_broadcast(current_user)
if @broadcast
# mark it as viewed
@broadcast.did_view(current_user)
respond_with_model(@broadcast)
else
render json: { message: 'Not Found'}, status: 404
end
end
# used to hide a broadcast notification from rotation temporarily
def quiet_broadcast_notification
@broadcast = BroadcastNotificationView.find_by_broadcast_notification_id_and_user_id(params[:broadcast_id], current_user.id)
if @broadcast
@broadcast.active_at = Date.today + 14 # 14 days in the future we'll re-instas
@broadcast.save
end
render json: { }, status: 200
end
###################### RECORDINGS #######################
# def recording_index
# @recordings = User.recording_index(current_user, params[:id])

View File

@ -0,0 +1,3 @@
object @broadcast
attributes :id, :message, :button_label, :button_url

View File

@ -9,6 +9,7 @@
<div class="dialog-overlay op70" style="display:none; width:100%; height:100%; z-index:99;"></div>
<%= render "header" %>
<%= react_component 'BroadcastHolder', {} %>
<%= render "home" %>
<%= render "footer" %>
<%= render "paginator" %>
@ -81,6 +82,7 @@
<%= render 'dialogs/dialogs' %>
<div id="fb-root"></div>
<script type="text/javascript">
$(function() {

8
web/bower.json Normal file
View File

@ -0,0 +1,8 @@
{
"vendor": {
"name": "bower-rails generated vendor assets",
"dependencies": {
"fluxxor": "1.5.4"
}
}
}

View File

@ -34,8 +34,10 @@ bundle install --path vendor/bundle
#bundle update
set +e
echo "cleaning assets from last build"
# clean assets, because they may be lingering from last build
bundle exec rake assets:clean
# bundle exec rake assets:clean
rm -rf $DIR/public/assets
if [ "$?" = "0" ]; then
echo "success: updated dependencies"

View File

@ -77,6 +77,7 @@ if defined?(Bundler)
# Add the assets/fonts directory to assets.paths
config.assets.paths << "#{Rails.root}/app/assets/fonts"
config.assets.paths << Rails.root.join('vendor', 'assets', 'bower_components')
# Precompile additional assets (application.js, application.css, and all non-JS/CSS (i.e., images) are already added)
config.assets.precompile += %w( client/client.css )
@ -85,7 +86,6 @@ if defined?(Bundler)
config.assets.precompile += %w( web/web.js web/web.css )
config.assets.precompile += %w( minimal/minimal.js minimal/minimal.css )
# where is rabbitmq?
config.rabbitmq_host = "localhost"
config.rabbitmq_port = 5672
@ -348,5 +348,8 @@ if defined?(Bundler)
config.web_performance_timing_enabled = true
config.jamtrack_landing_bubbles_enabled = true
config.jamtrack_browser_bubbles_enabled = true
config.react.variant = :production
config.react.addons = true
end
end

View File

@ -96,4 +96,6 @@ SampleApp::Application.configure do
config.email_generic_from = 'nobody-dev@jamkazam.com'
config.email_alerts_alias = ENV['ALERT_EMAIL'] || 'alerts-dev@jamkazam.com'
config.guard_against_fraud = true
config.react.variant = :development
end

View File

@ -374,6 +374,10 @@ SampleApp::Application.routes.draw do
match '/users/:id/share/session/:provider' => 'api_users#share_session', :via => :get
match '/users/:id/share/recording/:provider' => 'api_users#share_recording', :via => :get
# broadcast notification
match '/users/:id/broadcast_notification' => 'api_users#broadcast_notification', :via => :get
match '/users/:id/broadcast_notification/:broadcast_id/quiet' => 'api_users#quiet_broadcast_notification', :via => :post
# session chat
match '/chat' => 'api_chats#create', :via => :post
match '/sessions/:music_session/chats' => 'api_chats#index', :via => :get

16
web/package.json Normal file
View File

@ -0,0 +1,16 @@
{
"name": "jam-web",
"dependencies" : {
"browserify": "~> 6.3",
"browserify-incremental": "^1.4.0",
"coffeeify": "~> 0.6",
"reactify": "^0.17.1",
"coffee-reactify": "~>3.0.0",
"react": "^0.12.0",
"react-tools": "^0.12.1"
},
"engines": {
"node": ">= 0.10"
}
}

View File

@ -778,6 +778,13 @@ FactoryGirl.define do
end
end
factory :broadcast_notification, :class => JamRuby::BroadcastNotification do
title Faker::Lorem.sentence[0...50]
message Faker::Lorem.paragraph[0...200]
button_label Faker::Lorem.words(2).join(' ')[0...14]
frequency 3
end
factory :affiliate_partner, class: 'JamRuby::AffiliatePartner' do
sequence(:partner_name) { |n| "partner-#{n}" }
entity_type 'Individual'

View File

@ -0,0 +1,40 @@
require 'spec_helper'
describe "broadcast notification", :js => true, :type => :feature, :capybara_feature => true do
subject { page }
let(:broadcast1) {FactoryGirl.create(:broadcast_notification, frequency: 4)}
let(:broadcast2) {FactoryGirl.create(:broadcast_notification, frequency: 4)}
let(:user) { FactoryGirl.create(:user) }
let(:partner) { FactoryGirl.create(:affiliate_partner) }
before(:each) do
BroadcastNotificationView.delete_all
BroadcastNotification.delete_all
end
it "cycles on home screen" do
broadcast1.touch
fast_signin(user, '/client')
find('.broadcast-notification .message', text: broadcast1.message)
broadcast2.touch
visit current_path
find('.broadcast-notification .message', text: broadcast2.message)
visit current_path
find('.broadcast-notification .message', text: broadcast1.message)
find('.broadcast-notification .not-now').trigger(:click)
visit current_path
find('.broadcast-notification .message', text: broadcast2.message)
go_to_root
visit '/client'
find('.broadcast-notification .message', text: broadcast2.message)
end
end

File diff suppressed because one or more lines are too long