mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 17:45:40 -05:00
Starting SubscribeModal.
This commit is contained in:
parent
bf4c030d33
commit
15d7ac876a
10 changed files with 268 additions and 9 deletions
BIN
app/assets/images/pages/play/modal/subscribe-background.png
Normal file
BIN
app/assets/images/pages/play/modal/subscribe-background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 70 KiB |
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
top: 242px
|
top: 242px
|
||||||
width: 720px
|
width: 720px
|
||||||
height: 140px
|
height: 140px
|
||||||
index: 1
|
|
||||||
|
|
||||||
.product
|
.product
|
||||||
width: 228px
|
width: 228px
|
||||||
|
|
|
@ -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
|
||||||
|
|
139
app/styles/play/modal/subscribe-modal.sass
Normal file
139
app/styles/play/modal/subscribe-modal.sass
Normal 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
|
||||||
|
|
41
app/templates/play/modal/subscribe-modal.jade
Normal file
41
app/templates/play/modal/subscribe-modal.jade
Normal 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
|
|
@ -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']
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
67
app/views/play/modal/SubscribeModal.coffee
Normal file
67
app/views/play/modal/SubscribeModal.coffee
Normal 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()
|
||||||
|
)
|
Loading…
Reference in a new issue