livestream beta commit
This commit is contained in:
parent
9691d815cd
commit
b9681fd418
|
|
@ -64,7 +64,7 @@ gem 'resque-lonely_job', '~> 1.0.0'
|
|||
gem 'eventmachine', '1.2.3'
|
||||
gem 'amqp', '0.9.8'
|
||||
#gem 'logging-rails', :require => 'logging/rails'
|
||||
gem 'pg_migrate'
|
||||
gem 'pg_migrate', '0.1.14'
|
||||
gem 'ruby-protocol-buffers', '1.2.2'
|
||||
gem 'sendgrid', '1.2.0'
|
||||
gem 'geokit-rails'
|
||||
|
|
@ -84,7 +84,7 @@ gem 'stripe'
|
|||
gem 'zip-codes'
|
||||
gem 'email_validator'
|
||||
gem 'best_in_place' #, github: 'bernat/best_in_place'
|
||||
|
||||
gem 'auto_strip_attributes', '2.6.0'
|
||||
|
||||
|
||||
#group :libv8 do
|
||||
|
|
@ -126,9 +126,9 @@ end
|
|||
group :test do
|
||||
gem 'simplecov', '~> 0.7.1'
|
||||
gem 'simplecov-rcov'
|
||||
gem 'capybara-webkit'
|
||||
gem 'capybara-screenshot', '0.3.22' # 1.0.0 broke compat with rspec. maybe we need newer rspec
|
||||
gem 'poltergeist'
|
||||
# gem 'capybara-webkit'
|
||||
# gem 'capybara-screenshot', '0.3.22' # 1.0.0 broke compat with rspec. maybe we need newer rspec
|
||||
# gem 'poltergeist'
|
||||
end
|
||||
|
||||
gem 'pry'
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ GEM
|
|||
arel (6.0.4)
|
||||
arr-pm (0.0.10)
|
||||
cabin (> 0)
|
||||
auto_strip_attributes (2.6.0)
|
||||
activerecord (>= 4.0)
|
||||
aws-sdk (1.67.0)
|
||||
aws-sdk-v1 (= 1.67.0)
|
||||
aws-sdk-v1 (1.67.0)
|
||||
|
|
@ -114,13 +116,6 @@ GEM
|
|||
rack (>= 1.0.0)
|
||||
rack-test (>= 0.5.4)
|
||||
xpath (~> 2.0)
|
||||
capybara-screenshot (0.3.22)
|
||||
capybara (>= 1.0, < 3)
|
||||
colored
|
||||
launchy
|
||||
capybara-webkit (1.14.0)
|
||||
capybara (>= 2.3.0, < 2.14.0)
|
||||
json
|
||||
carrierwave (0.11.2)
|
||||
activemodel (>= 3.2.0)
|
||||
activesupport (>= 3.2.0)
|
||||
|
|
@ -134,7 +129,6 @@ GEM
|
|||
childprocess (0.8.0)
|
||||
ffi (~> 1.0, >= 1.0.11)
|
||||
clamp (1.0.1)
|
||||
cliver (0.3.2)
|
||||
cocoon (1.2.11)
|
||||
coderay (1.1.2)
|
||||
coffee-rails (4.2.2)
|
||||
|
|
@ -144,7 +138,6 @@ GEM
|
|||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.12.2)
|
||||
colored (1.2)
|
||||
concurrent-ruby (1.0.5)
|
||||
country-select (1.1.1)
|
||||
crass (1.0.3)
|
||||
|
|
@ -403,10 +396,6 @@ GEM
|
|||
insist
|
||||
mustache (= 0.99.8)
|
||||
stud
|
||||
poltergeist (1.17.0)
|
||||
capybara (~> 2.1)
|
||||
cliver (~> 0.3.1)
|
||||
websocket-driver (>= 0.2.0)
|
||||
polyamorous (1.3.3)
|
||||
activerecord (>= 3.0)
|
||||
postgres-copy (0.6.0)
|
||||
|
|
@ -610,9 +599,6 @@ GEM
|
|||
rack (>= 1.0.0)
|
||||
warden (1.2.7)
|
||||
rack (>= 1.0)
|
||||
websocket-driver (0.7.0)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.3)
|
||||
will_paginate (3.1.6)
|
||||
xdan-datetimepicker-rails (2.5.4)
|
||||
jquery-rails
|
||||
|
|
@ -629,6 +615,7 @@ DEPENDENCIES
|
|||
activeadmin
|
||||
activeadmin_addons
|
||||
amqp (= 0.9.8)
|
||||
auto_strip_attributes (= 2.6.0)
|
||||
aws-sdk (~> 1)
|
||||
bcrypt-ruby (= 3.0.1)
|
||||
best_in_place
|
||||
|
|
@ -636,8 +623,6 @@ DEPENDENCIES
|
|||
bootstrap-will_paginate (= 0.0.6)
|
||||
bugsnag
|
||||
capybara
|
||||
capybara-screenshot (= 0.3.22)
|
||||
capybara-webkit
|
||||
carrierwave (= 0.11.2)
|
||||
carrierwave_direct
|
||||
cocoon
|
||||
|
|
@ -669,8 +654,7 @@ DEPENDENCIES
|
|||
launchy
|
||||
mime-types (= 1.25)
|
||||
net-ssh
|
||||
pg_migrate
|
||||
poltergeist
|
||||
pg_migrate (= 0.1.14)
|
||||
postgres-copy (= 0.6.0)
|
||||
postgres_ext
|
||||
protected_attributes
|
||||
|
|
@ -708,4 +692,4 @@ DEPENDENCIES
|
|||
zip-codes
|
||||
|
||||
BUNDLED WITH
|
||||
1.13.7
|
||||
1.17.1
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
ActiveAdmin.register JamRuby::EventBriteOrder, :as => 'EventBriteOrder' do
|
||||
menu :parent => 'Misc'
|
||||
|
||||
config.sort_order = 'created_at DESC'
|
||||
|
||||
filter :live_stream
|
||||
filter :email
|
||||
filter :order_id
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
ActiveAdmin.register_page "EventBriteOrderUploads" do
|
||||
|
||||
menu :label => 'Event Brite Order Upload', :parent => 'Misc'
|
||||
|
||||
page_action :upload_eventbriteorders, :method => :post do
|
||||
EventBriteOrder.transaction do
|
||||
|
||||
puts params
|
||||
|
||||
|
||||
live_stream = LiveStream.find_by_id!(params[:jam_ruby_event_brite_order][:live_stream_id])
|
||||
|
||||
file = params[:jam_ruby_event_brite_order][:csv]
|
||||
|
||||
upload = EventBriteOrderUpload.new
|
||||
upload.upload_file_name = file.original_filename
|
||||
upload.save!
|
||||
|
||||
array_of_arrays = CSV.read(file.tempfile.path, headers:true)
|
||||
array_of_arrays.each do |row|
|
||||
order_id = row['Order ID']
|
||||
|
||||
event_brite_order = EventBriteOrder.find_by_order_id(order_id)
|
||||
if event_brite_order.nil?
|
||||
event_brite_order = EventBriteOrder.new
|
||||
end
|
||||
event_brite_order.event_brite_order_upload = upload
|
||||
event_brite_order.live_stream = live_stream
|
||||
event_brite_order.event_name = row['Event Name']
|
||||
event_brite_order.order_id = order_id
|
||||
event_brite_order.ticket_count = row['Tickets']
|
||||
event_brite_order.ticket_type = row['Type']
|
||||
event_brite_order.first_name = row['First Name']
|
||||
event_brite_order.last_name = row['Last Name']
|
||||
event_brite_order.email = row['Email Address']
|
||||
event_brite_order.save!
|
||||
end
|
||||
|
||||
redirect_to admin_eventbriteorderuploads_path, :notice => "Created #{array_of_arrays.length} event brite orders!"
|
||||
end
|
||||
end
|
||||
content do
|
||||
active_admin_form_for EventBriteOrder.new, :url => admin_eventbriteorderuploads_upload_eventbriteorders_path, :builder => ActiveAdmin::FormBuilder do |f|
|
||||
f.inputs "Upload Event Brite Orders" do
|
||||
f.input :csv, as: :file, required: true, :label => "An event brite order CSV exactly as exported from Eventbrite"
|
||||
f.input :live_stream, required:true, as: :select, :collection => LiveStream.upcoming
|
||||
end
|
||||
f.actions
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
ActiveAdmin.register JamRuby::LiveStream, :as => 'LiveStream' do
|
||||
menu :parent => 'Misc'
|
||||
|
||||
config.sort_order = 'created_at DESC'
|
||||
|
||||
filter :listed
|
||||
filter :event_id
|
||||
|
||||
before_build do |record|
|
||||
if !record.event_type.nil?
|
||||
puts "escape"
|
||||
else
|
||||
record.slug = 'please-do-this-sort-of-thing'
|
||||
record.starts_at = 10.days.from_now.midnight
|
||||
record.ends_at = 11.days.from_now.midnight
|
||||
record.img_width = 200
|
||||
record.event_type = 'eventbrite'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -30,3 +30,11 @@
|
|||
border:1px solid gray;
|
||||
padding:5px;
|
||||
}
|
||||
.datetime_select li.fragment {
|
||||
|
||||
|
||||
label {
|
||||
display: block;
|
||||
width:auto;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -391,3 +391,4 @@ limit_counter_reminders.sql
|
|||
amazon_v2.sql
|
||||
store_backend_details_rate_session.sql
|
||||
invited_user_receiver.sql
|
||||
live_streams.sql
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
CREATE TABLE live_streams (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
slug VARCHAR(512) NOT NULL UNIQUE,
|
||||
title TEXT,
|
||||
description TEXT,
|
||||
social_description TEXT,
|
||||
listed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
starts_at TIMESTAMP,
|
||||
ends_at TIMESTAMP,
|
||||
img_url VARCHAR(1024),
|
||||
img_width INTEGER,
|
||||
img_height INTEGER,
|
||||
youtube_code VARCHAR(1024),
|
||||
eventbriteid VARCHAR(1024),
|
||||
event_type VARCHAR(100),
|
||||
event_brite_registration_url VARCHAR(1024),
|
||||
allow_in BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
white_label_player BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
user_id VARCHAR(64) REFERENCES users(id) ON DELETE SET NULL,
|
||||
band_id VARCHAR(64) REFERENCES bands(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE event_brite_orders (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
live_stream_id VARCHAR(64) REFERENCES live_streams(id) ON DELETE CASCADE,
|
||||
event_brite_order_upload_id VARCHAR(64) REFERENCES event_brite_order_uploads(id) ON DELETE CASCADE,
|
||||
event_name VARCHAR(100) NOT NULL,
|
||||
order_id VARCHAR(100) NOT NULL UNIQUE,
|
||||
ticket_count INTEGER,
|
||||
ticket_type VARCHAR(100),
|
||||
first_name VARCHAR(100),
|
||||
last_name VARCHAR(100),
|
||||
email VARCHAR(200),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
times_claimed INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE event_brite_order_uploads (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
upload_file_name VARCHAR(500) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
|
@ -241,6 +241,9 @@ require "jam_ruby/models/jam_track_file"
|
|||
require "jam_ruby/models/jam_track_mixdown"
|
||||
require "jam_ruby/models/jam_track_mixdown_package"
|
||||
require "jam_ruby/models/genre_jam_track"
|
||||
require "jam_ruby/models/live_stream"
|
||||
require "jam_ruby/models/event_brite_order"
|
||||
require "jam_ruby/models/event_brite_order_upload"
|
||||
require "jam_ruby/app/mailers/async_mailer"
|
||||
require "jam_ruby/app/mailers/batch_mailer"
|
||||
require "jam_ruby/app/mailers/progress_mailer"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
class JamRuby::EventBriteOrder < ActiveRecord::Base
|
||||
|
||||
|
||||
belongs_to :live_stream, class_name: 'JamRuby::LiveStream'
|
||||
belongs_to :event_brite_order_upload, class_name: 'JamRuby::EventBriteOrderUpload'
|
||||
|
||||
validates :event_name, presence: true
|
||||
validates :order_id, presence: true
|
||||
validates :ticket_count, presence: true
|
||||
validates :ticket_type, presence: true
|
||||
|
||||
before_validation :sanitize
|
||||
|
||||
def sanitize
|
||||
self.first_name.strip! if self.first_name
|
||||
self.last_name.strip! if self.last_name
|
||||
self.email.strip! if self.email
|
||||
self.ticket_type.strip! if self.ticket_type
|
||||
self.order_id.strip! if self.order_id
|
||||
self.event_name.strip! if self.event_name
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
class JamRuby::EventBriteOrderUpload < ActiveRecord::Base
|
||||
has_many :event_brite_orders, class_name: 'JamRuby::EventBriteOrder'
|
||||
|
||||
validates :upload_file_name, presence: true
|
||||
end
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
class JamRuby::LiveStream < ActiveRecord::Base
|
||||
|
||||
attr_accessible :user_id, :band_id, :starts_at, :ends_at, :img_url, :slug, :title, :description, :listed, :allow_in, :white_label_player, :youtube_code, :eventbriteid, :event_type, :social_description, :event_brite_registration_url, as: :admin
|
||||
|
||||
#belongs_to :user, class_name: 'JamRuby::User'
|
||||
#belongs_to :band, class_name: 'JamRuby::Band'
|
||||
|
||||
#validate :one_of_user_band
|
||||
validates :slug, uniqueness: true, presence: true
|
||||
|
||||
before_validation :sanitize_active_admin
|
||||
|
||||
def ready_display
|
||||
self.starts_at && self.ends_at && (self.user_id || self.band_id)
|
||||
end
|
||||
|
||||
def self.upcoming
|
||||
LiveStream.where(listed: true).where("starts_at > ?", 2.days.ago).order('starts_at DESC')
|
||||
end
|
||||
|
||||
def sanitize_active_admin
|
||||
self.img_url = nil if self.img_url == ''
|
||||
self.user_id = nil if self.user_id == ''
|
||||
self.band_id = nil if self.band_id == ''
|
||||
self.social_description = nil if self.social_description == ''
|
||||
end
|
||||
|
||||
def one_of_user_band
|
||||
if band && user
|
||||
errors.add(:user, 'specify band, or user. not both')
|
||||
end
|
||||
end
|
||||
|
||||
def admin_name
|
||||
"#{title} EB:#{eventbriteid} #{starts_at}"
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
(function (context) {
|
||||
|
||||
/**
|
||||
* Javascript wrappers for the REST API
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var AuthorizedEventStorage = {}
|
||||
context.JK = context.JK || {};
|
||||
context.JK.AuthorizedEventStorage = AuthorizedEventStorage
|
||||
|
||||
var key = 'authorized_events'
|
||||
|
||||
AuthorizedEventStorage.storeAuthorizedEvent = (authorizedEvent) => {
|
||||
console.log("storing authorized event", authorizedEvent)
|
||||
var events = fetchFromStorage()
|
||||
if(!events) {
|
||||
events = {}
|
||||
}
|
||||
if(!events.list) {
|
||||
events.list = {}
|
||||
}
|
||||
|
||||
if(!authorizedEvent.event_id) {
|
||||
console.error("no event_id on new event", authorizedEvent)
|
||||
alert("Unable to store order (no event_id)! Please contact support@jamkazam.com.")
|
||||
return
|
||||
}
|
||||
if(!authorizedEvent.order_id) {
|
||||
console.error("no order_id on new event", authorizedEvent)
|
||||
alert("Unable to store order (no order_id)! Please contact support@jamkazam.com.")
|
||||
return
|
||||
}
|
||||
|
||||
events.list[authorizedEvent.event_id] = authorizedEvent
|
||||
|
||||
try {
|
||||
window.localStorage.setItem(key, JSON.stringify(events) )
|
||||
}
|
||||
catch(e) {
|
||||
console.error("can't update localStorage")
|
||||
alert("Could not update local storage ith order.\nPlease try a different browser. Please do not use incognito mode.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AuthorizedEventStorage.locateEvent = (eventId) => {
|
||||
var events = fetchFromStorage()
|
||||
if(events && events.list) {
|
||||
return events.list[eventId]
|
||||
}
|
||||
else {
|
||||
console.log("no events found in storage")
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
AuthorizedEventStorage.listAuthorizedEvents = () => {
|
||||
var events = fetchFromStorage()
|
||||
if(events) {
|
||||
return events.list
|
||||
}
|
||||
else {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
function fetchFromStorage() {
|
||||
var events = window.localStorage.getItem(key)
|
||||
if(events){
|
||||
try {
|
||||
return JSON.parse(events)
|
||||
}
|
||||
catch(e){
|
||||
console.log("events not parseable", events)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
})(window);
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
//= require ./jam_rest
|
||||
//= require ./authorized_event_storage
|
||||
//= require reflux
|
||||
//= require react
|
||||
//= require react_ujs
|
||||
//= require react-init
|
||||
//= require react-input-autosize
|
||||
//= require react-select
|
||||
//= require ./react-components
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
(function (context) {
|
||||
|
||||
/**
|
||||
* Javascript wrappers for the REST API
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var Rest2 = {}
|
||||
context.JK = context.JK || {};
|
||||
context.JK.Rest2 = Rest2
|
||||
|
||||
Rest2.listLiveStreams = () => {
|
||||
return fetch('/api/live_streams', {
|
||||
method: 'get',
|
||||
credentials: 'same-origin', // include, *same-origin, omit
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
})
|
||||
}
|
||||
Rest2.getLiveStream = (id) => {
|
||||
return fetch('/api/live_streams/' + id, {
|
||||
method: 'get',
|
||||
credentials: 'same-origin', // include, *same-origin, omit
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
Rest2.authorizeLiveStream = (data) => {
|
||||
return fetch('/api/live_streams/claim', {
|
||||
method: 'post',
|
||||
credentials: 'same-origin', // include, *same-origin, omit
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
cache: 'no-cache',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
})(window);
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
//= require_directory ./react-components/actions
|
||||
//= require ./react-components/stores/EventStore
|
||||
//= require_directory ./react-components
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
context = window
|
||||
EventActions = context.EventActions
|
||||
|
||||
context.EventList = React.createClass({
|
||||
|
||||
mixins: [Reflux.listenTo(EventStore, "onEventsChanged")],
|
||||
|
||||
events: null,
|
||||
|
||||
getInitialState: function () {
|
||||
return {events: null}
|
||||
},
|
||||
|
||||
componentDidMount: function () {
|
||||
},
|
||||
|
||||
isModeYours: function() {
|
||||
return this.props.mode == 'yours'
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return this.renderAll();
|
||||
},
|
||||
|
||||
|
||||
renderEvents() {
|
||||
if(!this.state.events || this.state.events.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var items = []
|
||||
|
||||
|
||||
var isModeYours = this.isModeYours();
|
||||
for(var i = 0; i < this.state.events.length; i++) {
|
||||
var event = this.state.events[i]
|
||||
|
||||
if(isModeYours && (!!event.authorization || event.allow_in) || !isModeYours && (!event.authorization && !event.allow_in)) {
|
||||
|
||||
var dynamic = null
|
||||
var thumb = null
|
||||
if(event.img_url) {
|
||||
thumb = <img className="thumb" src={event.img_url} />
|
||||
dynamic = 'event'
|
||||
}
|
||||
else {
|
||||
dynamic = 'event no-image'
|
||||
}
|
||||
|
||||
var title = event.title ? event.title : 'Missing event title'
|
||||
title = <a className="title-link" href={"/events/" + event.slug}>{title}</a>
|
||||
var when = event.starts_at ? new Date(event.starts_at).toLocaleString() : 'Unknown start time'
|
||||
var item = <div className={dynamic} key={event.id}>
|
||||
{thumb}
|
||||
<div className="detail">
|
||||
<div className="title">{title}</div>
|
||||
<div className="when">{when}</div>
|
||||
</div>
|
||||
</div>
|
||||
items.push(item)
|
||||
}
|
||||
}
|
||||
return items
|
||||
},
|
||||
|
||||
renderAll: function() {
|
||||
var events = this.renderEvents()
|
||||
var headerText = this.isModeYours() ? 'Your Registered Events' : 'All Upcoming Events'
|
||||
|
||||
if(!events || events.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if(events) {
|
||||
var response = <div className="EventList">
|
||||
<div className="event-header">
|
||||
{headerText}
|
||||
</div>
|
||||
|
||||
<div className="event-section">
|
||||
{events}
|
||||
</div>
|
||||
</div>
|
||||
return response
|
||||
}
|
||||
else {
|
||||
return <div className="EventList">
|
||||
<div className="event-header">
|
||||
{headerText}
|
||||
</div>
|
||||
|
||||
<div className="event-section loading">
|
||||
Loading ...
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
},
|
||||
|
||||
onEventsChanged: function (allEvents) {
|
||||
var scopedEvents = []
|
||||
if(this.isModeYours()) {
|
||||
allEvents.events.entries.forEach(function(event) {
|
||||
if (event.authorization || event.allow_in) {
|
||||
scopedEvents.push(event)
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
scopedEvents = allEvents.events.entries
|
||||
}
|
||||
|
||||
|
||||
this.setState({events: scopedEvents})
|
||||
}
|
||||
})
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
context = window
|
||||
EventActions = context.EventActions
|
||||
|
||||
context.EventPage = React.createClass({
|
||||
|
||||
mixins: [Reflux.listenTo(EventStore, "onEventsChanged")],
|
||||
|
||||
|
||||
getInitialState: function () {
|
||||
return {submitting: false, error: null, event: null}
|
||||
},
|
||||
|
||||
parseSlug: function() {
|
||||
var path = window.location.pathname
|
||||
|
||||
console.log("slug path: ", path)
|
||||
|
||||
var pathPart = path.substring('/events/'.length)
|
||||
console.log("slug part", pathPart)
|
||||
|
||||
var query = pathPart.indexOf('?')
|
||||
if(query > -1) {
|
||||
var slug = pathPart.substring(0, query)
|
||||
}
|
||||
else {
|
||||
var slug = pathPart
|
||||
}
|
||||
|
||||
|
||||
console.log("slug", slug)
|
||||
return slug;
|
||||
|
||||
},
|
||||
|
||||
componentDidMount: function () {
|
||||
EventActions.single(this.parseSlug())
|
||||
// new Plyr('#video');
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
|
||||
},
|
||||
|
||||
authorizeDone: function(response) {
|
||||
this.setState({submitting:false})
|
||||
EventActions.addAuthorization(response)
|
||||
},
|
||||
|
||||
authorizeFailed: function(e) {
|
||||
if(e instanceof SyntaxError) {
|
||||
this.setState({error: 'Server error. Please try again or contact support@jamkazam.com.'})
|
||||
}
|
||||
else if(e instanceof Error) {
|
||||
this.setState({error: 'Please enter a valid Eventbrite Order ID'})
|
||||
}
|
||||
else {
|
||||
console.log("heheh", e)
|
||||
}
|
||||
this.setState({submitting:false})
|
||||
},
|
||||
|
||||
handleSubmit: function(event) {
|
||||
var value = document.getElementById("order-input").value
|
||||
if(value) {
|
||||
context.JK.Rest2.authorizeLiveStream({order: value}).then((response) => {
|
||||
if (!response.ok) {
|
||||
throw Error(response.statusText);
|
||||
}
|
||||
return response.json()
|
||||
}).then((response) => this.authorizeDone(response)).catch((jqXHR) => this.authorizeFailed(jqXHR))
|
||||
this.setState({submitting: true, error:null})
|
||||
}
|
||||
event.preventDefault();
|
||||
},
|
||||
|
||||
isErrored() {
|
||||
return !!this.state.error
|
||||
},
|
||||
|
||||
isReady() {
|
||||
return !!this.state.event
|
||||
},
|
||||
|
||||
isAuthorized() {
|
||||
return this.state.event.authorization || this.state.event.allow_in
|
||||
},
|
||||
|
||||
isNotAuthorized() {
|
||||
return false
|
||||
},
|
||||
|
||||
videoCode() {
|
||||
return this.state.event.youtube_code
|
||||
},
|
||||
|
||||
title() {
|
||||
return this.state.event.title ? this.state.event.title : 'Unknown title'
|
||||
},
|
||||
|
||||
description() {
|
||||
return this.state.event.description ? this.state.event.description : ''
|
||||
},
|
||||
|
||||
startsAt() {
|
||||
return this.state.event.starts_at? "Starts at " + new Date(this.state.event.starts_at).toLocaleString() : 'Unknown start time'
|
||||
},
|
||||
|
||||
header() {
|
||||
|
||||
if(this.isErrored()) {
|
||||
return <div className="header">
|
||||
<div className="title">No event found.</div>
|
||||
</div>
|
||||
}
|
||||
else if(this.isReady()) {
|
||||
var title = this.title()
|
||||
var description = this.description()
|
||||
var startsAt = this.startsAt()
|
||||
|
||||
return <div className="header">
|
||||
<div className="title">{title}</div>
|
||||
<div className="description">{description}</div>
|
||||
<div className="starts-at">{startsAt}</div>
|
||||
</div>
|
||||
}
|
||||
else {
|
||||
return <div className="header">
|
||||
<div className="title">Loading ...</div>
|
||||
</div>
|
||||
}
|
||||
},
|
||||
|
||||
body: function() {
|
||||
var video = null
|
||||
if(this.isErrored()) {
|
||||
video = null
|
||||
}
|
||||
else if(this.isReady()) {
|
||||
if(this.isAuthorized()) {
|
||||
//video = <div id="player" className="video player">
|
||||
// <div id="video" data-plyr-provider="youtube" data-plyr-embed-id={this.videoCode()}></div>
|
||||
//</div>
|
||||
|
||||
var videoCode = this.videoCode()
|
||||
if(videoCode) {
|
||||
var src = "https://www.youtube.com/embed/" + this.videoCode() + "?modestbranding=true&autoplay=0&rel=0"
|
||||
video = <div id="player">
|
||||
<iframe src={src} frameBorder="0" style={ { position:"absolute", top:0,left:0,width:"100%", height:"100%"} } allow="accelerometer; encrypted-media; gyroscope; autoplay" allowFullScreen={true}></iframe>
|
||||
</div>
|
||||
}
|
||||
else {
|
||||
video = <div id="no-player" className="no-code"><div>No video yet</div></div>
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
var notRegistered = <span className="no-register">You are not registered for this event!</span>
|
||||
var onceDone = <li>Enter your EventBrite order code at the <a href="https://www.jamkazam.com/events" target="_blank"> JamKazam Event Registration</a> page when done registering.</li>
|
||||
|
||||
var eventBriteUrl = this.state.event.event_brite_registration_url
|
||||
if(eventBriteUrl) {
|
||||
var meat = <div>
|
||||
{notRegistered}
|
||||
<ol>
|
||||
<li>Please register at <a target="_blank" href={eventBriteUrl}>EventBrite</a> to see this video</li>
|
||||
{onceDone}
|
||||
</ol>
|
||||
</div>
|
||||
}
|
||||
else {
|
||||
var meat = <div>
|
||||
{notRegistered}
|
||||
<ol>
|
||||
<li>Please find your event at <a target="_blank" href="https://www.eventbrite.com/d/online/jamkazam/">EventBrite</a> and register for this event.</li>
|
||||
{onceDone}
|
||||
</ol>
|
||||
</div>
|
||||
}
|
||||
video = <div id="no-player" className="no-code">
|
||||
{meat}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else {
|
||||
video = <div id="no-player"></div>
|
||||
}
|
||||
|
||||
return video
|
||||
},
|
||||
|
||||
render: function () {
|
||||
|
||||
var header = this.header()
|
||||
|
||||
var body = this.body()
|
||||
|
||||
var response = <div className="EventPage">
|
||||
<div id="header">
|
||||
<div className="logo-holder"><img src="/assets/logo.png"/></div>
|
||||
</div>
|
||||
<div id="top-container">
|
||||
{header}
|
||||
</div>
|
||||
<div className="listing">
|
||||
{body}
|
||||
</div>
|
||||
</div>
|
||||
return response
|
||||
},
|
||||
|
||||
onEventsChanged: function (allEvents) {
|
||||
var event = null;
|
||||
if(allEvents && allEvents.events && allEvents.events.entries && allEvents.events.entries.length > 0){
|
||||
event = allEvents.events.entries[0]
|
||||
}
|
||||
|
||||
console.log("event change", event, allEvents)
|
||||
this.setState({event: event, error:allEvents.events_error})
|
||||
}
|
||||
})
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
context = window
|
||||
EventActions = context.EventActions
|
||||
|
||||
context.EventsPage = React.createClass({
|
||||
|
||||
getInitialState: function () {
|
||||
return {submitting: false, error: null}
|
||||
},
|
||||
|
||||
componentDidMount: function () {
|
||||
EventActions.refresh()
|
||||
},
|
||||
|
||||
authorizeDone: function(response) {
|
||||
this.setState({submitting:false})
|
||||
EventActions.addAuthorization(response)
|
||||
},
|
||||
|
||||
authorizeFailed: function(e) {
|
||||
if(e instanceof SyntaxError) {
|
||||
this.setState({error: 'Server error. Please try again or contact support@jamkazam.com.'})
|
||||
}
|
||||
else if(e instanceof Error) {
|
||||
this.setState({error: 'Please enter a valid Eventbrite Order ID'})
|
||||
}
|
||||
else {
|
||||
console.log("heheh", e)
|
||||
}
|
||||
this.setState({submitting:false})
|
||||
},
|
||||
|
||||
handleSubmit: function(event) {
|
||||
var value = document.getElementById("order-input").value
|
||||
if(value) {
|
||||
context.JK.Rest2.authorizeLiveStream({order: value}).then((response) => {
|
||||
if (!response.ok) {
|
||||
throw Error(response.statusText);
|
||||
}
|
||||
return response.json()
|
||||
}).then((response) => this.authorizeDone(response)).catch((jqXHR) => this.authorizeFailed(jqXHR))
|
||||
this.setState({submitting: true, error:null})
|
||||
}
|
||||
event.preventDefault();
|
||||
},
|
||||
render: function () {
|
||||
|
||||
var ctaButtonClasses = "cta-button"
|
||||
if(this.state.submitting) {
|
||||
ctaButtonClasses = ctaButtonClasses + " submitting"
|
||||
}
|
||||
var errorClasses = "error"
|
||||
if(this.state.error) {
|
||||
errorClasses = errorClasses + " active"
|
||||
}
|
||||
var response = <div className="EventsPage">
|
||||
<div id="header">
|
||||
<div className="logo-holder"><img src="/assets/logo.png"/></div>
|
||||
</div>
|
||||
<div id="top-container">
|
||||
<div className="header">
|
||||
<p>Enter your order number from<img className="eventbrite-logo" src="/assets/event/eventbrite-logo.png"/>below:</p>
|
||||
</div>
|
||||
<div className="submit-row">
|
||||
<div className="submit promo-start">
|
||||
<form id="unlock" onSubmit={this.handleSubmit}>
|
||||
<input type="text" name="order" className="order-input" id="order-input"/>
|
||||
<button className={ctaButtonClasses}>Unlock Livestream</button>
|
||||
</form>
|
||||
<span className={errorClasses}>{this.state.error}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="listings">
|
||||
<div className="preview-and-action-box">
|
||||
<div id="upcoming-yours">
|
||||
<EventList mode="yours"/>
|
||||
</div>
|
||||
<div id="upcoming-all">
|
||||
<EventList mode="all"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
return response
|
||||
},
|
||||
|
||||
})
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
@EventActions = Reflux.createActions({
|
||||
refresh: {},
|
||||
single: {}
|
||||
addAuthorization: {}
|
||||
})
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
context = window
|
||||
|
||||
console.log(@EventActions)
|
||||
console.log(window.EventActions)
|
||||
|
||||
@EventStore = Reflux.createStore(
|
||||
{
|
||||
listenables: window.EventActions
|
||||
|
||||
events: null
|
||||
eventsError: null
|
||||
eventStorage: null
|
||||
AuthorizedEventsStorage: null
|
||||
|
||||
init: ->
|
||||
@AuthorizedEventStorage = context.JK.AuthorizedEventStorage
|
||||
|
||||
changed: () ->
|
||||
state = @getState()
|
||||
@trigger(state)
|
||||
|
||||
addAuthorization: (authorization) ->
|
||||
@AuthorizedEventStorage.storeAuthorizedEvent(authorization)
|
||||
@collateEvents()
|
||||
|
||||
onRefresh: () ->
|
||||
context.JK.Rest2.listLiveStreams().then((response) => response.json()).then((response) => @refreshDone(response)).catch((jqXHR) => @refreshFailed(jqXHR))
|
||||
|
||||
onSingle: (slug) ->
|
||||
context.JK.Rest2.getLiveStream(slug).then((response) => response.json()).then((response) =>
|
||||
console.log("single", response)
|
||||
if(response.errors)
|
||||
@refreshFailed(response)
|
||||
else
|
||||
matchedFormat = {entries:[ response ]}
|
||||
@refreshDone(matchedFormat))
|
||||
|
||||
.catch((jqXHR) => @refreshFailed(jqXHR))
|
||||
|
||||
refreshDone: (events) ->
|
||||
|
||||
@eventsError = false
|
||||
@events = events
|
||||
@collateEvents()
|
||||
|
||||
refreshFailed: (events) ->
|
||||
console.log("events error", events)
|
||||
@eventsError = true
|
||||
@changed()
|
||||
|
||||
collateEvents: () ->
|
||||
authorizedEvents = @AuthorizedEventStorage.listAuthorizedEvents()
|
||||
|
||||
for event in @events.entries
|
||||
|
||||
authorization = authorizedEvents[event.id]
|
||||
if authorization
|
||||
console.log("event is authorized", event)
|
||||
event.authorization = authorization
|
||||
else
|
||||
event.authorization = null
|
||||
|
||||
@changed()
|
||||
|
||||
getState:() ->
|
||||
{events: @events, events_error: @eventsError}
|
||||
|
||||
}
|
||||
)
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
var defaultURL = 'http://127.0.0.1:3000/signup'; //<---- CHANGE TO YOUR WEBSITE URL
|
||||
|
||||
//show loading graphic
|
||||
function showLoader(id) {
|
||||
$('#' + id + ' img').fadeIn('slow');
|
||||
}
|
||||
|
||||
//hdie loading graphic
|
||||
function hideLoader(id) {
|
||||
$('#' + id + ' img').fadeOut('slow');
|
||||
}
|
||||
|
||||
//function to check load state of each frame
|
||||
function allLoaded(){
|
||||
var results = [];
|
||||
$('iframe').each(function(){
|
||||
if(!$(this).data('loaded')){results.push(false)}
|
||||
});
|
||||
var result = (results.length > 0) ? false : true;
|
||||
return result;
|
||||
};
|
||||
|
||||
function loadPage($frame, url) {
|
||||
if ( url.substr(0,7) !== 'http://' && url.substr(0,8) !== 'https://' && url.substr(0, 7) !== 'file://' ) {
|
||||
url = 'http://'+url;
|
||||
}
|
||||
$('iframe').not($frame).each(function(){showLoader($(this).parent().attr('id'));})
|
||||
$('iframe').not($frame).data('loaded', false);
|
||||
$('iframe').not($frame).attr('src', url);
|
||||
}
|
||||
|
||||
$('.frame').each(function(){showLoader($(this).attr('id'))});
|
||||
|
||||
|
||||
//when document loads
|
||||
$(document).ready(function(){
|
||||
|
||||
loadPage('', defaultURL);
|
||||
|
||||
//query string
|
||||
var qsArray = window.location.href.split('?');
|
||||
var qs = qsArray[qsArray.length-1];
|
||||
|
||||
if(qs != '' && qsArray.length > 1){
|
||||
$('#url input[type=text]').val(qs);
|
||||
loadPage('', qs);
|
||||
}
|
||||
|
||||
//set slidable div width
|
||||
$('#frames #inner').css('width', function(){
|
||||
var width = 0;
|
||||
$('.frame').each(function(){width += $(this).outerWidth() + 20});
|
||||
return width;
|
||||
});
|
||||
|
||||
//add event handlers for options radio buttons
|
||||
$('input[type=radio]').change(function(){
|
||||
$frames = $('#frames');
|
||||
$inputs = $('input[type=radio]:checked').val();
|
||||
|
||||
if($inputs == '1'){
|
||||
$frames.addClass('widthOnly');
|
||||
} else {
|
||||
$frames.removeClass('widthOnly');
|
||||
}
|
||||
});
|
||||
|
||||
//add event handlers for scrollbars checkbox
|
||||
$('input[type=checkbox]').change(function(){
|
||||
var scrollBarWidth = 15;
|
||||
$frames = $('#frames');
|
||||
$inputs = $('#scrollbar:checked');
|
||||
|
||||
if( $inputs.length == 0 ){
|
||||
scrollBarWidth = -15;
|
||||
}
|
||||
|
||||
$frames.find('iframe').each(function(i,el) {
|
||||
$(el).attr('width', parseInt($(el).attr('width')) + scrollBarWidth);
|
||||
});
|
||||
});
|
||||
|
||||
//when the url textbox is used
|
||||
$('form').submit(function(){
|
||||
loadPage('' , $('#url input[type=text]').val());
|
||||
return false;
|
||||
});
|
||||
|
||||
//when frame loads
|
||||
$('iframe').load(function(){
|
||||
|
||||
var $this = $(this);
|
||||
var url = '';
|
||||
var error = false;
|
||||
|
||||
try{
|
||||
url = $this.contents().get(0).location.href;
|
||||
} catch(e) {
|
||||
error = true;
|
||||
if($('#url input[type=text]').val() != ''){
|
||||
url = $('#url input[type=text]').val();
|
||||
} else {
|
||||
url = defaultURL;
|
||||
}
|
||||
}
|
||||
|
||||
//load other pages with the same URL
|
||||
if(allLoaded()){
|
||||
if(error){
|
||||
alert('Browsers prevent navigation from inside iframes across domains.\nPlease use the textbox at the top for external sites.');
|
||||
loadPage('', defaultURL);
|
||||
}else{
|
||||
loadPage($this, url);
|
||||
}
|
||||
}
|
||||
|
||||
//when frame loads, hide loader graphic
|
||||
else{
|
||||
error = false;
|
||||
hideLoader($(this).parent().attr('id'));
|
||||
$(this).data('loaded',true);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -232,8 +232,9 @@
|
|||
}
|
||||
|
||||
if(networkTest.length) {
|
||||
stepNetworkTest.initialize($wizardSteps.filter($('.network-test')), self);
|
||||
STEPS[dynamicStepCount++] = stepNetworkTest
|
||||
// skip network test always
|
||||
//stepNetworkTest.initialize($wizardSteps.filter($('.network-test')), self);
|
||||
//STEPS[dynamicStepCount++] = stepNetworkTest
|
||||
}
|
||||
|
||||
STEPS[dynamicStepCount++]=stepSuccess
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
$base-font-family: 'arial', sans-serif;
|
||||
|
||||
$large-font-size: 1.5rem;
|
||||
$standard-font-size: 1rem;
|
||||
$smaller-font-size: .8rem;
|
||||
$small-font-size: .7rem;
|
||||
$input-font-size: 1.0rem;
|
||||
$submit-button-width:9rem;
|
||||
$checkbox-label-width:14rem;
|
||||
$create-account-width:10rem;
|
||||
$start-promo-btn-width:13rem;
|
||||
$jamkazam-background:#323232;
|
||||
|
||||
$copy-color-on-dark: #b9b9b9;
|
||||
$copy-color-on-white: #575757;
|
||||
$cta-color: #e03d04;
|
||||
$chunkyBorderWidth: 6px;
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
|
||||
*= require dialogs/banner
|
||||
*= require_directory ./react-components
|
||||
*/
|
||||
|
||||
@import "events/constants";
|
||||
|
||||
html,
|
||||
body {
|
||||
min-height: 100%;
|
||||
overflow:auto;
|
||||
background-color:$jamkazam-background;
|
||||
color:white;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
font-size: 16px;
|
||||
line-height: 1.2;
|
||||
font-family: Raleway, Arial, Helvetica, sans-serif;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
@import "events/constants";
|
||||
@import "client/common.scss";
|
||||
|
||||
.EventList {
|
||||
|
||||
.event-header {
|
||||
background-color: $cta-color;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
border-width: $chunkyBorderWidth 0 $chunkyBorderWidth;
|
||||
border-style: solid;
|
||||
border-color: $copy-color-on-dark;
|
||||
}
|
||||
|
||||
.event-section {
|
||||
padding: 10px;
|
||||
//s border-width: 0 0 $chunkyBorderWidth;
|
||||
//border-style: solid;
|
||||
//border-color: $copy-color-on-dark;
|
||||
|
||||
&.loading {
|
||||
text-align:center;
|
||||
}
|
||||
}
|
||||
|
||||
.event {
|
||||
display:grid;
|
||||
grid-template-columns: 10rem 20rem;
|
||||
align-content:center;
|
||||
height:8rem;
|
||||
border-style: solid;
|
||||
border-width: 2px 0 2px 0;
|
||||
border-color: $copy-color-on-dark;
|
||||
|
||||
&:first-child {
|
||||
border-width:0 0 1px 0;
|
||||
}
|
||||
&:last-child {
|
||||
border-width:1px 0 0 0;
|
||||
}
|
||||
&:only-child {
|
||||
border-width:0;
|
||||
}
|
||||
|
||||
&.no-image {
|
||||
grid-template-columns: 30rem;
|
||||
}
|
||||
}
|
||||
|
||||
.title-link {
|
||||
color:white;
|
||||
}
|
||||
img.thumb {
|
||||
width:100%;
|
||||
max-height:400px;
|
||||
}
|
||||
div.thumb {
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
text-transform: uppercase;
|
||||
padding-right:1rem;
|
||||
}
|
||||
|
||||
.detail {
|
||||
display:grid;
|
||||
justify-content: center;
|
||||
padding-left:1rem;
|
||||
align-content:center;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size:1.5rem;
|
||||
}
|
||||
|
||||
.when {
|
||||
font-size:1rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
@import "events/constants";
|
||||
@import "client/common.scss";
|
||||
|
||||
|
||||
[data-react-class="EventPage"] {
|
||||
width:100%;
|
||||
|
||||
.EventPage {
|
||||
width:100%;
|
||||
}
|
||||
|
||||
#header {
|
||||
display:grid;
|
||||
justify-content: center;
|
||||
width:100%;
|
||||
background-color:$jamkazam-background;
|
||||
padding:1.5rem 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size:2rem;
|
||||
}
|
||||
|
||||
.description {
|
||||
color:gray;
|
||||
font-size:1rem;
|
||||
margin-top:.2rem;
|
||||
}
|
||||
|
||||
.starts-at {
|
||||
color:gray;
|
||||
font-size:1rem;
|
||||
margin-top:.2rem;
|
||||
}
|
||||
#root {
|
||||
min-height: 100%;
|
||||
|
||||
align-items: center;
|
||||
//justify-content: center;
|
||||
min-width: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#player, #no-player {
|
||||
position:relative;
|
||||
padding-bottom:56.25%;
|
||||
padding-top:30px;
|
||||
height:0;
|
||||
overflow:hidden;
|
||||
top:-5rem;
|
||||
border-width: $chunkyBorderWidth;
|
||||
border-style: solid;
|
||||
border-color: $copy-color-on-dark;
|
||||
a {
|
||||
color:#fc0;
|
||||
}
|
||||
}
|
||||
|
||||
#no-player {
|
||||
display:grid;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.no-register {
|
||||
text-decoration: underline;
|
||||
font-weight:bold;
|
||||
margin-top:2rem;
|
||||
display:block;
|
||||
}
|
||||
|
||||
.no-code {
|
||||
background-color: black;
|
||||
padding-bottom:0 !important;
|
||||
height:auto !important;
|
||||
min-height:200px !important;
|
||||
padding-top:0 !important;
|
||||
text-align:center;
|
||||
font-size:1rem;
|
||||
ul,ol {
|
||||
text-align:left;
|
||||
}
|
||||
}
|
||||
#top-container {
|
||||
background-color:black;
|
||||
display: grid;
|
||||
justify-content:center;
|
||||
padding:2rem 0 7rem 0;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
div.root {
|
||||
flex-grow: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.listing {
|
||||
width:50%;
|
||||
margin:auto;
|
||||
//display:grid;
|
||||
//justify-content: center;
|
||||
}
|
||||
|
||||
|
||||
@media (min-width:1px) and (max-width: 1199px) {
|
||||
html {
|
||||
font-size: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
@import "events/constants";
|
||||
@import "client/common.scss";
|
||||
|
||||
|
||||
[data-react-class="EventsPage"] {
|
||||
width:100%;
|
||||
|
||||
.EventsPage {
|
||||
width:100%;
|
||||
}
|
||||
|
||||
#header {
|
||||
display:grid;
|
||||
justify-content: center;
|
||||
width:100%;
|
||||
background-color:$jamkazam-background;
|
||||
padding:1.5rem 0;
|
||||
}
|
||||
|
||||
#root {
|
||||
min-height: 100%;
|
||||
|
||||
align-items: center;
|
||||
//justify-content: center;
|
||||
min-width: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.order-input {
|
||||
font-size:1rem;
|
||||
padding:5px;
|
||||
}
|
||||
|
||||
.cta-button {
|
||||
cursor:pointer;
|
||||
font-size: 1rem;
|
||||
color: white;
|
||||
background-color: $cta-color;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
margin-left:5px;
|
||||
border-radius: 8px;
|
||||
border: 1px outset buttonface;
|
||||
font-family: Raleway, Arial, Helvetica, sans-serif;
|
||||
|
||||
&.submitting {
|
||||
background-color: gray;
|
||||
}
|
||||
}
|
||||
.error {
|
||||
margin-top: 1rem;
|
||||
#position: absolute;
|
||||
display:none;
|
||||
color:red;
|
||||
font-weight:bold;
|
||||
&.active {
|
||||
display:inline;
|
||||
}
|
||||
}
|
||||
.eventbrite-logo {
|
||||
height:2rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
#top-container {
|
||||
background-color:black;
|
||||
display: grid;
|
||||
justify-content:center;
|
||||
padding:5rem 0 7rem 0;
|
||||
}
|
||||
|
||||
div.root {
|
||||
flex-grow: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.logo-holder {
|
||||
max-width: 300px;
|
||||
min-width:0;
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.submit-row {
|
||||
text-align:center;
|
||||
}
|
||||
p {
|
||||
margin:.5rem 0;
|
||||
}
|
||||
p:first-child {
|
||||
margin-top:0;
|
||||
}
|
||||
p.last-child {
|
||||
margin-bottom:0;
|
||||
}
|
||||
|
||||
.header {
|
||||
font-size: $large-font-size;
|
||||
margin-top: 1rem;
|
||||
width: 100%;
|
||||
max-width: 700px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.listings {
|
||||
display:grid;
|
||||
justify-content: center;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.preview-and-action-box {
|
||||
background-color: black;
|
||||
position:relative;
|
||||
top: -2rem;
|
||||
min-width: 400px;
|
||||
@include border_box_sizing;
|
||||
border-width: 0 $chunkyBorderWidth $chunkyBorderWidth;
|
||||
border-style: solid;
|
||||
border-color: $copy-color-on-dark;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@media (min-width:1px) and (max-width: 1199px) {
|
||||
html {
|
||||
font-size: 100%;
|
||||
}
|
||||
.code-input {
|
||||
max-width:$submit-button-width;
|
||||
}
|
||||
.code-input input {
|
||||
font-size: $standard-font-size;
|
||||
}
|
||||
.code-instructions {
|
||||
width:$submit-button-width;
|
||||
}
|
||||
|
||||
.text-input input {
|
||||
width:$create-account-width;
|
||||
}
|
||||
.select-input select{
|
||||
width:$create-account-width;
|
||||
}
|
||||
|
||||
.instructions.create-account {
|
||||
margin-top:1rem;
|
||||
text-align:justify;
|
||||
}
|
||||
.success-msg {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.logo-holder.create-account {
|
||||
margin-top:2rem;
|
||||
}
|
||||
.code-form.create-account {
|
||||
margin-top:1rem;
|
||||
}
|
||||
.powered-by.create-account {
|
||||
margin-top:0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
class ApiLiveStreamsController < ApiController
|
||||
|
||||
|
||||
respond_to :json
|
||||
|
||||
def log
|
||||
@log || Logging.logger[ApiLiveStreamsController]
|
||||
end
|
||||
|
||||
|
||||
def index
|
||||
@live_streams = LiveStream.upcoming
|
||||
|
||||
render "api_live_streams/index", :layout => nil
|
||||
end
|
||||
|
||||
def claim
|
||||
order = params[:order]
|
||||
if order.nil?
|
||||
render :json => {}, :status => 404, layout: nil
|
||||
return
|
||||
end
|
||||
|
||||
order.strip!
|
||||
|
||||
if order.start_with? "#"
|
||||
order = order[1..-1]
|
||||
end
|
||||
|
||||
event_brite_order = EventBriteOrder.find_by_order_id(order)
|
||||
|
||||
if event_brite_order.nil?
|
||||
render :json => {}, :status => 404, layout: nil
|
||||
else
|
||||
EventBriteOrder.where(id: event_brite_order.id).update_all(times_claimed: event_brite_order.times_claimed + 1)
|
||||
render :json => {event_id: event_brite_order.live_stream.id, order_id: event_brite_order.order_id, event_type: 'eventbrite'}, :status => :ok, layout: nil
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
slug = params[:slug]
|
||||
@live_stream = LiveStream.find_by_slug!(slug)
|
||||
render "api_live_streams/show", :layout => nil
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -2,7 +2,20 @@ class EventsController < ApplicationController
|
|||
|
||||
respond_to :html
|
||||
|
||||
|
||||
def list
|
||||
render 'events', layout: 'events'
|
||||
end
|
||||
|
||||
|
||||
def show
|
||||
@event = LiveStream.find_by_slug(params[:slug])
|
||||
|
||||
render 'event', :layout => 'events'
|
||||
end
|
||||
|
||||
# 2014 lulz
|
||||
def show_old
|
||||
@event = Event.find_by_slug!(params[:slug])
|
||||
render 'event', :layout => "web"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ class SpikesController < ApplicationController
|
|||
render :layout => false
|
||||
end
|
||||
|
||||
def responsive
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def subscription
|
||||
|
||||
#Notification.send_reload(MessageFactory::ALL_NATIVE_CLIENTS)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
node :entries do |page|
|
||||
partial "api_live_streams/show", object: @live_streams
|
||||
end
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
object @live_stream
|
||||
|
||||
attributes :id, :slug, :title, :description, :starts_at, :allow_in, :ends_at, :img_url, :img_width, :img_height, :youtube_code, :eventbriteid, :event_type, :event_brite_registration_url, :white_label_player
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
- provide(:page_name, 'JamKazam Event')
|
||||
- provide(:description, @description)
|
||||
- provide(:title, @title)
|
||||
|
||||
#root
|
||||
= react_component 'EventPage'
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
- provide(:page_name, 'Upcoming JamKazam Events')
|
||||
- provide(:description, @description)
|
||||
- provide(:title, @title)
|
||||
|
||||
#root
|
||||
= react_component 'EventsPage'
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><%= full_title(yield(:title)) %></title>
|
||||
|
||||
<!--[if IE]>
|
||||
<link rel="stylesheet" type="text/css" href="css/ie.css" media="screen, projection"/>
|
||||
<![endif]-->
|
||||
<link href='http://fonts.googleapis.com/css?family=Raleway:100,200,300,400,500,600,700' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" href="https://cdn.plyr.io/3.5.10/plyr.css" />
|
||||
<%= stylesheet_link_tag "events/events", media: "all" %>
|
||||
<%= include_gon(:init => true) %>
|
||||
<%= csrf_meta_tags %>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta name="description" content="<%= meta_description(yield(:description)) %>">
|
||||
<% if content_for?(:social_meta) %>
|
||||
<%= yield(:social_meta) %>
|
||||
<% else %>
|
||||
<%= render "layouts/social_meta" %>
|
||||
<% end %>
|
||||
<%= render "shared/ad_sense" %>
|
||||
</head>
|
||||
<body class="events <%= yield(:page_name) %>">
|
||||
<div id="basic-container">
|
||||
<!--<script src="https://cdn.plyr.io/3.5.10/plyr.polyfilled.js"></script>-->
|
||||
<%= javascript_include_tag "events/events" %>
|
||||
<div class="wrapper">
|
||||
<%= yield %>
|
||||
<div id="rt-e617b4394e0e49e1c234c63161bb2e15"></div> <script src="https://rumbletalk.com/client/?VHi@pnno"></script>
|
||||
</div>
|
||||
</div>
|
||||
<%= render "clients/help" %>
|
||||
<%= render 'dialogs/banner' %>
|
||||
<%= render "shared/ga" %>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" content="Responsive design testing for the masses">
|
||||
<title>Responsive Design Testing</title>
|
||||
<style>
|
||||
*{vertical-align:top;}
|
||||
body{padding:20px;font-family:sans-serif;overflow-y:scroll;}
|
||||
h2{margin:0 0 20px 0;}
|
||||
span.small{font-size:60%;vertical-align:middle;}
|
||||
#url{margin:0 0 20px 0px;display:block;}
|
||||
#url input[type=text]{border:solid 1px #666;width:85%;margin:0 auto;font-size:2em;text-align:left;}
|
||||
#url input[type=submit]{display:none;}
|
||||
#url #options{float:right;line-height:25px;width:13%;}
|
||||
#url #options input{margin-top:5px;}
|
||||
#frames{overflow-x:scroll;width:100%;margin-bottom:10px;padding-bottom:20px;}
|
||||
.frame{margin-right:20px;float:left;}
|
||||
.frame:last-child{margin-right:0;}
|
||||
.frame img{display:none;vertical-align:middle;}
|
||||
iframe{border:solid 1px #000;}
|
||||
.widthOnly {height:580px;}
|
||||
.widthOnly h2 span{display:none;}
|
||||
.widthOnly iframe{height:500px;}
|
||||
</style>
|
||||
</head>
|
||||
<body id="container">
|
||||
<div id="url">
|
||||
<form method="post">
|
||||
<input type="text" placeholder="Test your own site... type the url and hit enter" />
|
||||
<input type="submit" value="submit">
|
||||
<div id="options">
|
||||
<label for="normal"><input id="normal" type="radio" name="option" value="1" checked>Width only</label><br />
|
||||
<label for="accurate"><input id="accurate" type="radio" name="option" value="2">Device sizes</label><br />
|
||||
<label for="scrollbar"><input id="scrollbar" type="checkbox" name="scrollbar" value="1" checked>Visible Scrollbars</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="frames" class="widthOnly">
|
||||
<div id="inner">
|
||||
<div id="f1" class="frame">
|
||||
<h2>240<span> x 320</span> <span class="small">(small phone)</span> <img src="http://mattkersley.com/wp-content/themes/mattkersley/images/loader_large.gif" /></h2>
|
||||
<iframe sandbox="allow-same-origin allow-forms allow-scripts" seamless width="255" height="320"></iframe>
|
||||
</div>
|
||||
<div id="f2" class="frame">
|
||||
<h2>320<span> x 480</span> <span class="small">(iPhone)</span> <img src="http://mattkersley.com/wp-content/themes/mattkersley/images/loader_large.gif" /></h2>
|
||||
<iframe sandbox="allow-same-origin allow-forms allow-scripts" seamless width="335" height="480"></iframe>
|
||||
</div>
|
||||
<div id="f3" class="frame">
|
||||
<h2>480<span> x 640</span> <span class="small">(small tablet)</span> <img src="http://mattkersley.com/wp-content/themes/mattkersley/images/loader_large.gif" /></h2>
|
||||
<iframe sandbox="allow-same-origin allow-forms allow-scripts" seamless width="495" height="640"></iframe>
|
||||
</div>
|
||||
<div id="f4" class="frame">
|
||||
<h2>768<span> x 1024</span> <span class="small">(iPad - Portrait)</span> <img src="http://mattkersley.com/wp-content/themes/mattkersley/images/loader_large.gif" /></h2>
|
||||
<iframe sandbox="allow-same-origin allow-forms allow-scripts" seamless width="783" height="1024"></iframe>
|
||||
</div>
|
||||
<div id="f5" class="frame">
|
||||
<h2>1024<span> x 768</span> <span class="small">(iPad - Landscape)</span> <img src="http://mattkersley.com/wp-content/themes/mattkersley/images/loader_large.gif" /></h2>
|
||||
<iframe sandbox="allow-same-origin allow-forms allow-scripts" seamless width="1039" height="768"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span>A tool by <a href="http://mattkersley.com">Matt Kersley</a> - <a href="https://github.com/mattkersley/Responsive-Design-Testing">Fork it on Github</a></span><br />
|
||||
<span>Note: The content width may not be pixel perfect - I have added 15px to the iframes to cater for the scrollbars</span>
|
||||
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js"></script>
|
||||
<%= javascript_include_tag "spikes/responsive.js" %>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -131,6 +131,7 @@ Rails.application.routes.draw do
|
|||
get '/gmail_contacts', to: 'gmail#gmail_contacts'
|
||||
|
||||
get '/events/:slug', to: 'events#show', :as => 'event'
|
||||
get '/events', to: 'events#list', as: 'events'
|
||||
|
||||
get '/endorse/:id/:service', to: 'users#endorse', :as => 'endorse'
|
||||
|
||||
|
|
@ -143,6 +144,7 @@ Rails.application.routes.draw do
|
|||
require 'resque-retry/server'
|
||||
mount Resque::Server.new, :at => "/resque" if Rails.env == "development"
|
||||
|
||||
get '/responsive', to: 'spikes#responsive'
|
||||
# route to spike controller (proof-of-concepts)
|
||||
get '/listen_in', to: 'spikes#listen_in'
|
||||
get '/facebook_invite', to: 'spikes#facebook_invite'
|
||||
|
|
@ -229,6 +231,11 @@ Rails.application.routes.draw do
|
|||
|
||||
post '/auths/login' => 'api_auths#login'
|
||||
|
||||
# live streams
|
||||
match '/live_streams' => 'api_live_streams#index', :via => :get
|
||||
match '/live_streams/claim' => 'api_live_streams#claim', :via => :post
|
||||
match '/live_streams/:slug' => 'api_live_streams#show', :via => :get
|
||||
|
||||
# music sessions
|
||||
match '/sessions/:id/participants/legacy' => 'api_music_sessions#participant_create_legacy', :via => :post # can be removed when new Create Session comes in
|
||||
match '/sessions/:id/participants' => 'api_music_sessions#participant_create', :via => :post
|
||||
|
|
|
|||
Loading…
Reference in New Issue