Starting SubscribeModal.

This commit is contained in:
Nick Winter 2014-12-02 20:01:53 -08:00
parent bf4c030d33
commit 15d7ac876a
10 changed files with 268 additions and 9 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View file

@ -332,6 +332,11 @@
prompt_body: "Do you want to get more?" prompt_body: "Do you want to get more?"
prompt_button: "Enter Shop" prompt_button: "Enter Shop"
subscribe:
subscribe_title: "Subscribe"
subscribe_button: "$9.99/mo - Subscribe"
stripe_description: "Monthly Subscription"
choose_hero: choose_hero:
choose_hero: "Choose Your Hero" choose_hero: "Choose Your Hero"
programming_language: "Programming Language" programming_language: "Programming Language"

View file

@ -115,7 +115,7 @@ html.no-borderimage #cast-button-view
border: 0 border: 0
&.submit-button, &.done-button &.submit-button, &.done-button
background-image: url(/images/level/code_toolbar_submit_button_active_pressed.png) background-image: url(/images/level/code_toolbar_submit_button_active.png)
border: 0 border: 0
&:active &:active

View file

@ -22,7 +22,6 @@
top: 242px top: 242px
width: 720px width: 720px
height: 140px height: 140px
index: 1
.product .product
width: 228px width: 228px

View file

@ -28,7 +28,7 @@ $heroCanvasHeight: 265px
left: 154px left: 154px
top: 25px top: 25px
margin: 0 margin: 0
width: 350px width: 450px
text-align: center text-align: center
color: rgb(254,188,68) color: rgb(254,188,68)
font-size: 38px font-size: 38px

View file

@ -0,0 +1,139 @@
@import "app/styles/mixins"
@import "app/styles/bootstrap/variables"
#subscribe-modal
//- Clear modal defaults
.modal-dialog
margin: 60px auto 0 auto
padding: 0
width: 746px
height: 520px
background: none
//- Background
#subscribe-background
position: absolute
top: -61px
left: 0px
//- Header
h1
position: absolute
left: 150px
top: 25px
margin: 0
width: 410px
text-align: center
color: rgb(254,188,68)
font-size: 38px
text-shadow: black 4px 4px 0, black -4px -4px 0, black 4px -4px 0, black -4px 4px 0, black 4px 0px 0, black 0px -4px 0, black -4px 0px 0, black 0px 4px 0, black 6px 6px 6px
font-variant: normal
text-transform: uppercase
//- Close modal button
#close-modal
position: absolute
left: 568px
top: 17px
width: 60px
height: 60px
color: white
text-align: center
font-size: 30px
padding-top: 15px
cursor: pointer
@include rotate(-3deg)
&:hover
color: yellow
//- Selling points
#selling-points
position: absolute
left: 55px
top: 142px
width: 681px
height: 140px
.point
width: 150px
height: 256px
overflow: none
float: left
text-align: center
margin-right: 10px
background-color: rgba(156, 204, 10, 0.2)
h4
font-size: 20px
color: rgb(22,16,5)
h3
margin-top: 10px
text-transform: uppercase
color: rgb(22,16,5)
button
width: 80%
//- Purchase button
.purchase-button
position: absolute
left: 73px
width: 600px
height: 70px
top: 430px
font-size: 32px
line-height: 42px
border-image: url(/images/level/code_toolbar_submit_button_active.png) 14 20 20 20 fill round
border-width: 14px 20px 20px 20px
color: darken(white, 5%)
span
pointer-events: none
&:hover
border-image: url(/images/level/code_toolbar_submit_button_zazz.png) 14 20 20 20 fill round
color: white
&:active
border-image: url(/images/level/code_toolbar_submit_button_zazz_pressed.png) 14 20 20 20 fill round
padding: 2px 0 0 2px
color: white
//- Errors
.alert
position: absolute
left: 10%
width: 80%
top: 20px
border: 5px solid gray
html.no-borderimage #subscribe-modal
.purchase-button
border: 0
background-image: url(/images/level/code_toolbar_submit_button_active.png)
background-size: 100% 100%
padding: 7px 10px 10px 10px
&:hover
background-image: url(/images/level/code_toolbar_submit_button_zazz.png)
border: 0
&:active
background-image: url(/images/level/code_toolbar_submit_button_zazz_pressed.png)
padding: 9px 8px 8px 12px
border: 0

View file

@ -0,0 +1,41 @@
.modal-dialog
.modal-content
if state === 'purchasing'
.alert.alert-info(data-i18n="buy_gems.purchasing")
else if state === 'retrying'
#retrying-alert.alert.alert-danger(data-i18n="buy_gems.retrying")
else
img(src="/images/pages/play/modal/subscribe-background.png")#subscribe-background
h1(data-i18n="subscribe.subscribe_title") Subscribe
div#close-modal
span.glyphicon.glyphicon-remove
#selling-points
#point-levels.point
.blurb 25 more levels. 5 new levels every week.
#point-heroes.point
.blurb 13 more heroes to unleash on the ogre hordes.
#point-items.point
.blurb 275 items to unlock and explore.
#point-gems.point
.blurb Subscribers get 3500 bonus gems per month.
button.btn.btn-lg.btn-illustrated.purchase-button(data-i18n="subscribe.subscribe_button")
span $9.99/mo - Subscribe
if state === 'declined'
#declined-alert.alert.alert-danger.alert-dismissible
span(data-i18n="buy_gems.declined")
button.close(type="button" data-dismiss="alert")
span(aria-hidden="true") ×
if state === 'unknown_error'
#error-alert.alert.alert-danger.alert-dismissible
button.close(type="button" data-dismiss="alert")
span(aria-hidden="true") ×
p(data-i18n="loading_error.unknown")
p= stateMessage

View file

@ -9,6 +9,7 @@ ThangType = require 'models/ThangType'
MusicPlayer = require 'lib/surface/MusicPlayer' MusicPlayer = require 'lib/surface/MusicPlayer'
storage = require 'core/storage' storage = require 'core/storage'
AuthModal = require 'views/core/AuthModal' AuthModal = require 'views/core/AuthModal'
SubscribeModal = require 'views/play/modal/SubscribeModal'
trackedHourOfCode = false trackedHourOfCode = false
@ -77,6 +78,8 @@ module.exports = class WorldMapView extends RootView
$('body').append($('<img src="http://code.org/api/hour/begin_codecombat.png" style="visibility: hidden;">')) $('body').append($('<img src="http://code.org/api/hour/begin_codecombat.png" style="visibility: hidden;">'))
trackedHourOfCode = true trackedHourOfCode = true
@requiresSubscription = me.isAdmin() and @terrain isnt 'dungeon' and not me.get('stripe')?.subscriptionID
destroy: -> destroy: ->
@setupManager?.destroy() @setupManager?.destroy()
$(window).off 'resize', @onWindowResize $(window).off 'resize', @onWindowResize
@ -112,6 +115,8 @@ module.exports = class WorldMapView extends RootView
@fullyRendered = true @fullyRendered = true
@render() @render()
@preloadTopHeroes() unless me.get('heroConfig')?.thangType @preloadTopHeroes() unless me.get('heroConfig')?.thangType
if @requiresSubscription
_.delay (=> @openModalView? new SubscribeModal() unless window.currentModal), 2000
getRenderData: (context={}) -> getRenderData: (context={}) ->
context = super(context) context = super(context)
@ -145,7 +150,7 @@ module.exports = class WorldMapView extends RootView
@$el.find('.level').tooltip() @$el.find('.level').tooltip()
@$el.addClass _.string.slugify @terrain @$el.addClass _.string.slugify @terrain
@updateVolume() @updateVolume()
unless window.currentModal or not @fullyRendered unless window.currentModal or not @fullyRendered or @requiresSubscription
@highlightElement '.level.next', delay: 500, duration: 60000, rotation: 0, sides: ['top'] @highlightElement '.level.next', delay: 500, duration: 60000, rotation: 0, sides: ['top']
if levelID = @$el.find('.level.next').data('level-id') if levelID = @$el.find('.level.next').data('level-id')
@$levelInfo = @$el.find(".level-info-container[data-level-id=#{levelID}]").show() @$levelInfo = @$el.find(".level-info-container[data-level-id=#{levelID}]").show()
@ -182,20 +187,23 @@ module.exports = class WorldMapView extends RootView
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
@$levelInfo?.hide() @$levelInfo?.hide()
levelElement = $(e.target).parents('.level')
levelID = levelElement.data('level-id')
campaign = _.find campaigns, id: @terrain
level = _.find campaign.levels, id: levelID
if application.isIPadApp if application.isIPadApp
levelID = $(e.target).parents('.level').data('level-id')
@$levelInfo = @$el.find(".level-info-container[data-level-id=#{levelID}]").show() @$levelInfo = @$el.find(".level-info-container[data-level-id=#{levelID}]").show()
@adjustLevelInfoPosition e @adjustLevelInfoPosition e
@endHighlight() @endHighlight()
else else
if $(e.target).attr('disabled') if @requiresSubscription
@openModalView new SubscribeModal()
else if $(e.target).attr('disabled')
Backbone.Mediator.publish 'router:navigate', route: '/contribute/adventurer' Backbone.Mediator.publish 'router:navigate', route: '/contribute/adventurer'
return return
else if $(e.target).parent().hasClass 'locked' else if $(e.target).parent().hasClass 'locked'
return return
else else
levelElement = $(e.target).parents('.level')
levelID = levelElement.data('level-id')
@startLevel levelElement @startLevel levelElement
window.tracker?.trackEvent 'Clicked Level', category: 'World Map', levelID: levelID, ['Google Analytics'] window.tracker?.trackEvent 'Clicked Level', category: 'World Map', levelID: levelID, ['Google Analytics']

View file

@ -57,7 +57,7 @@ module.exports = class BuyGemsModal extends ModalView
Backbone.Mediator.publish 'buy-gems-modal:purchase-initiated', { productID: productID } Backbone.Mediator.publish 'buy-gems-modal:purchase-initiated', { productID: productID }
else else
application.tracker?.trackEvent 'Started purchase', {productID:productID}, ['Google Analytics'] application.tracker?.trackEvent 'Started purchase', { productID: productID }
stripeHandler.open({ stripeHandler.open({
description: $.t(product.i18n) description: $.t(product.i18n)
amount: product.amount amount: product.amount

View file

@ -0,0 +1,67 @@
ModalView = require 'views/core/ModalView'
template = require 'templates/play/modal/subscribe-modal'
stripeHandler = require 'core/services/stripe'
utils = require 'core/utils'
module.exports = class SubscribeModal extends ModalView
id: 'subscribe-modal'
template: template
plain: true
closesOnClickOutside: false
product:
amount: 999
id: 'basic_subscription'
subscriptions:
'stripe:received-token': 'onStripeReceivedToken'
events:
'click .purchase-button': 'onClickPurchaseButton'
'click #close-modal': 'hide'
constructor: (options) ->
super(options)
@state = 'standby'
getRenderData: ->
c = super()
c.state = @state
c.stateMessage = @stateMessage
return c
onClickPurchaseButton: (e) ->
@playSound 'menu-button-click'
application.tracker?.trackEvent 'Started subscription purchase', {}
stripeHandler.open({
description: $.t 'subscribe.stripe_description'
amount: @product.amount
})
onStripeReceivedToken: (e) ->
@timestampForPurchase = new Date().getTime()
data = {
productID: @product.id
stripe: {
token: e.token.id
timestamp: @timestampForPurchase
}
}
@state = 'purchasing'
@render()
jqxhr = $.post('/db/payment', data)
jqxhr.done(=>
document.location.reload()
)
jqxhr.fail(=>
if jqxhr.status is 402
@state = 'declined'
@stateMessage = arguments[2]
else if jqxhr.status is 500
@state = 'retrying'
f = _.bind @onStripeReceivedToken, @, e
_.delay f, 2000
else
@state = 'unknown_error'
@stateMessage = "#{jqxhr.status}: #{jqxhr.responseText}"
@render()
)