365 lines
16 KiB
CoffeeScript
365 lines
16 KiB
CoffeeScript
context = window
|
|
rest = context.JK.Rest()
|
|
logger = context.JK.logger
|
|
LocationActions = context.LocationActions
|
|
SubscriptionActions = context.SubscriptionActions
|
|
UserStore = context.UserStore
|
|
AppStore = context.AppStore
|
|
|
|
@CurrentSubscription = React.createClass({
|
|
|
|
mixins: [Reflux.listenTo(AppStore, "onAppInit")]
|
|
|
|
getInitialState: () ->
|
|
{
|
|
selectedPlan: null
|
|
updating: false
|
|
}
|
|
|
|
getDisplayNameTier: (plan_code) ->
|
|
if plan_code == ''
|
|
plan_code = null
|
|
for subscriptionCode in gon.global.subscription_codes
|
|
if plan_code == subscriptionCode.id
|
|
return subscriptionCode.name
|
|
return "Unknown plan code=#{plan_code}"
|
|
|
|
getDisplayNamePrice: (plan_code) ->
|
|
if plan_code == ''
|
|
plan_code = null
|
|
for subscriptionCode in gon.global.subscription_codes
|
|
if plan_code == subscriptionCode.id
|
|
return subscriptionCode.price
|
|
return "Unknown plan code=#{plan_code}"
|
|
|
|
getDisplayCycle:(plan_code) ->
|
|
if plan_code == ''
|
|
plan_code = null
|
|
for subscriptionCode in gon.global.subscription_codes
|
|
if plan_code == subscriptionCode.id
|
|
if subscriptionCode.cycle == "year"
|
|
return "annual"
|
|
else
|
|
return subscriptionCode.cycle + "ly"
|
|
return "Unknown plan code=#{plan_code}"
|
|
|
|
onPlanChanged: (e) ->
|
|
val = e.target.value
|
|
@originalPlan = this.currentPlan()
|
|
@setState({selectedPlan: val})
|
|
|
|
currentPlan: () ->
|
|
if this.state.selectedPlan?
|
|
this.state.selectedPlan
|
|
else
|
|
this.props.subscription.desired_plan_code || ''
|
|
|
|
checkIfPending:() ->
|
|
return this.state.selectedPlan?
|
|
|
|
onSubmit: (event) ->
|
|
if event
|
|
event.preventDefault()
|
|
@prePerformSubmit()
|
|
|
|
onChangeSubmit: (form) ->
|
|
if @state.updating
|
|
return
|
|
@prePerformSubmit()
|
|
|
|
cancelChangePlan:() ->
|
|
console.log("cancel change plan", @originalPlan)
|
|
@setState({selectedPlan: @originalPlan })
|
|
# user selects button on main page
|
|
onUpdatePaymentMethod: () ->
|
|
if gon.isNativeClient
|
|
context.JK.popExternalLink("/client#/account/paymentHistory", true)
|
|
else
|
|
window.location.href = "/client#/account/paymentHistory"
|
|
|
|
openBrowserToPayment: () ->
|
|
if gon.isNativeClient
|
|
context.JK.popExternalLink("/client#/account/paymentHistory", true)
|
|
else
|
|
window.location.href = "/client#/account/paymentHistory"
|
|
|
|
prePerformSubmit:() ->
|
|
if !@state.selectedPlan?
|
|
return
|
|
|
|
message = null
|
|
if this.props.subscription.subscription
|
|
if this.state.selectedPlan == null || this.state.selectedPlan == ''
|
|
message = "<p>You have chosen to go back down to the FREE PLAN. Your subscription will be canceled, and you will keep your plan until the end of the current billing cycle.</p>"
|
|
else
|
|
message = "<p>You have selected the #{this.getDisplayNameTier(this.state.selectedPlan).toUpperCase()} #{this.getDisplayCycle(this.state.selectedPlan).toUpperCase()} PLAN and will be charged US$#{this.getDisplayNamePrice(this.state.selectedPlan)} on the start of next billing cycle.</p>"
|
|
else
|
|
if this.state.selectedPlan == null || this.state.selectedPlan == ''
|
|
@performSubmit()
|
|
return
|
|
else
|
|
message = "<p>You have selected the #{this.getDisplayNameTier(this.state.selectedPlan).toUpperCase()} #{this.getDisplayCycle(this.state.selectedPlan).toUpperCase()} PLAN and will be charged US$#{this.getDisplayNamePrice(this.state.selectedPlan)} .</p>"
|
|
|
|
buttons = []
|
|
buttons.push({
|
|
name: 'CANCEL',
|
|
buttonStyle: 'button-grey',
|
|
click: (() => (@cancelChangePlan()))
|
|
})
|
|
buttons.push({
|
|
name: 'CONFIRM',
|
|
buttonStyle: 'button-orange',
|
|
click: (() => (@performSubmit()))
|
|
})
|
|
context.JK.Banner.show({
|
|
title: "Confirm Plan Change",
|
|
html: message,
|
|
buttons: buttons})
|
|
|
|
performSubmit: () ->
|
|
@setState({updating: true})
|
|
#SubscriptionActions.changeSubscription(this.state.selectedPlan)
|
|
rest.changeSubscription(this.state.selectedPlan).done((subscription) =>
|
|
SubscriptionActions.forceUpdate(subscription)
|
|
has_billing_info = subscription.has_billing_info
|
|
console.log("subscription change update", subscription)
|
|
@setState({updating: false, selectedPlan: null})
|
|
if has_billing_info
|
|
@props.app.layout.notify({
|
|
title: "Subscription updated!",
|
|
text: "Thank you for supporting JamKazam!"
|
|
})
|
|
else
|
|
if subscription.desired_plan_code
|
|
if gon.isNativeClient
|
|
html = context._.template($('#template-payment-still-needed-native').html(), {}, { variable: 'data' })
|
|
else
|
|
html = context._.template($('#template-payment-still-needed').html(), {}, { variable: 'data' })
|
|
|
|
buttons = []
|
|
buttons.push({name: 'CLOSE', buttonStyle: 'button-grey'})
|
|
buttons.push({
|
|
name: 'UPDATE PAYMENT METHOD',
|
|
buttonStyle: 'button-orange',
|
|
click: (() => (@openBrowserToPayment()))
|
|
})
|
|
context.JK.Banner.show({
|
|
title: "Payment Method Needed",
|
|
html: html,
|
|
buttons: buttons})
|
|
else
|
|
@props.app.layout.notify({
|
|
title: "Subscription updated!",
|
|
text: "Thank you for supporting JamKazam!"
|
|
})
|
|
|
|
#@props.app.layout.notify({
|
|
# title: "Payment method still needed",
|
|
# text: "Please click UPDATE PAYMENT METHOD in the bottom-right of the screen."
|
|
#})
|
|
|
|
)
|
|
.fail((jqXHR) =>
|
|
@setState({updating: false})
|
|
if jqXHR.status == 422
|
|
@props.app.layout.notify({
|
|
title: "you already have this subscription",
|
|
text: "No changes were made to your account."
|
|
})
|
|
else
|
|
@props.app.layout.notify({
|
|
title: "unable to update subscription status",
|
|
text: "Please contact support@jamkazam.com. Error:\n #{jqXHR.responseText}"
|
|
})
|
|
)
|
|
|
|
onCancelPlan: (event) ->
|
|
if confirm("Are you sure you want to cancel your plan?")
|
|
SubscriptionActions.cancelSubscription()
|
|
|
|
componentDidMount: () ->
|
|
|
|
@root = $(@getDOMNode())
|
|
|
|
document.querySelector('#change-subscription-form').addEventListener('submit', @onChangeSubmit.bind(this))
|
|
|
|
|
|
getTimeRemaining: (t) ->
|
|
|
|
if t < 0
|
|
t = -t
|
|
|
|
seconds = Math.floor( (t/1000) % 60 );
|
|
minutes = Math.floor( (t/1000/60) % 60 );
|
|
hours = Math.floor( (t/(1000*60*60)) % 24 );
|
|
days = Math.floor( t/(1000*60*60*24) );
|
|
|
|
return {
|
|
'total': t,
|
|
'days': days,
|
|
'hours': hours,
|
|
'minutes': minutes,
|
|
'seconds': seconds
|
|
};
|
|
|
|
|
|
displayTime: (until_time) ->
|
|
|
|
if until_time < 0
|
|
return 'no time'
|
|
|
|
untilTime = @getTimeRemaining(until_time * 1000)
|
|
|
|
timeString = ''
|
|
if untilTime.days != 0
|
|
timeString += "#{untilTime.days} days, "
|
|
if untilTime.hours != 0 || timeString.length > 0
|
|
timeString += "#{untilTime.hours} hours, "
|
|
if untilTime.minutes != 0 || timeString.length > 0
|
|
timeString += "#{untilTime.minutes} minutes "
|
|
#if untilTime.seconds != 0 || timeString.length > 0
|
|
# timeString += "#{untilTime.seconds} seconds"
|
|
|
|
if timeString == ''
|
|
'now!'
|
|
timeString
|
|
|
|
comparePlans: (e) ->
|
|
if context.JK.clientType() == 'client'
|
|
context.JK.popExternalLink("https://jamkazam.freshdesk.com/support/solutions/articles/66000122535-what-are-jamkazam-s-free-vs-premium-features-")
|
|
e.preventDefault()
|
|
|
|
# comparePlans: `function(e) {
|
|
# if (context.JK.clientType() === 'client') {
|
|
# context.JK.popExternalLink("https://jamkazam.freshdesk.com/support/solutions/articles/66000122535-what-are-jamkazam-s-free-vs-premium-features-");
|
|
# return e.preventDefault();
|
|
# }
|
|
# }`
|
|
|
|
render: () ->
|
|
plan_codes = []
|
|
monthlies = []
|
|
yearlies = []
|
|
for plan in gon.global.subscription_codes
|
|
if plan.cycle == 'month'
|
|
monthlies.push(plan)
|
|
else
|
|
yearlies.push(plan)
|
|
plan_codes.push(`<option key="monthly" value="monthly" disabled="disabled">-------- MONTHLY PLANS --------</option>`)
|
|
for plan in monthlies
|
|
plan_codes.push(`<option key={plan.id || ''} value={plan.id || ''}>{plan.name} (${plan.price.toFixed(2)}/{plan.cycle})</option>`)
|
|
plan_codes.push(`<option key="yearly" value="yearly" disabled="disabled">-------- YEARLY PLANS --------</option>`)
|
|
for plan in yearlies
|
|
plan_codes.push(`<option key={plan.id || ''} value={plan.id || ''}>{plan.name} (${plan.price.toFixed(2)}/{plan.cycle})</option>`)
|
|
plansJsx = `<select name="plan_code" onChange={this.onPlanChanged} defaultValue={this.currentPlan()} value={this.currentPlan()}>{plan_codes}</select>`
|
|
|
|
changeClass = 'button-orange update-plan'
|
|
if !@state.selectedPlan? || @state.updating
|
|
changeClass = changeClass + ' disabled'
|
|
|
|
if @state.updating
|
|
update_plan_text = 'UPDATING PLAN ... PLEASE WAIT'
|
|
else
|
|
update_plan_text = 'UPDATE PLAN'
|
|
|
|
|
|
recurly_subscription = @props.subscription.subscription
|
|
effective_plan_name = `<span className="plan-name">{this.getDisplayNameTier(this.props.subscription.plan_code)}</span>`
|
|
desired_plan_name = `<span className="plan-name">{this.getDisplayNameTier(this.props.subscription.desired_plan_code)}</span>`
|
|
admin_override_plan_name = `<span className="plan-name">{this.getDisplayNameTier(this.props.subscription.admin_override_plan_code)}</span>`
|
|
in_trial = @props.subscription.in_trial
|
|
admin_override = @props.subscription.admin_override_plan_code?
|
|
effective_is_free = !!this.props.subscription.plan_code
|
|
has_pending_subscription = @props.subscription.subscription?.pending_subscription?
|
|
cancelled_subscription = @props.subscription.subscription?.remaining_billing_cycles == 0
|
|
show_payment_info = null
|
|
has_billing_info = @props.subscription.has_billing_info
|
|
|
|
|
|
if admin_override
|
|
explanation = `<span>You have a {effective_plan_name} account until your gifted plan ends {context.JK.formatDateShort(this.props.subscription.admin_override_ends_at)}.</span>`
|
|
else if in_trial
|
|
if @props.subscription.desired_plan_code
|
|
if has_billing_info
|
|
note = `<span>Billing starts for the {desired_plan_name} plan after the trial ends.</span>`
|
|
else
|
|
warning = `<p className="uncollectable-msg">You will drop to the <span className="plan-name">Free</span> free plan after the trial ends because you have not yet entered payment info.</p>`
|
|
show_payment_info = true
|
|
else
|
|
if has_billing_info
|
|
warning = `<p className="uncollectable-msg">You will drop to the <span className="plan-name">Free</span> free plan after the trial ends because you have not selected a plan.</p>`
|
|
else
|
|
warning = `<p className="uncollectable-msg">You will drop to the <span className="plan-name">Free</span> free plan after the trial ends because you have not yet entered payment info or selected a plan.</p>`
|
|
show_payment_info = true
|
|
|
|
explanation = `<span>You have a {effective_plan_name} account until your trial ends {context.JK.formatDateShort(this.props.subscription.trial_ends_at)}. {note}</span>`
|
|
else
|
|
if @props.subscription.desired_plan_code && !@props.subscription.plan_code && !has_billing_info
|
|
explanation = `<span>You have successfully upgraded your plan to the {desired_plan_name} level, thank you!</span>`
|
|
warning = `<p className="uncollectable-msg">For this plan to take effect, you must provide a payment method (e.g. a credit card), for the monthly subscription charge. Please click the Update Payment Method button to do this now.</p>`
|
|
show_payment_info = true
|
|
else
|
|
if @props.subscription.desired_plan_code
|
|
if !has_billing_info
|
|
show_payment_info = true
|
|
explanation = `<span>You have successfully upgraded your plan to the {desired_plan_name} level, thank you</span>`
|
|
warning = `<p className="uncollectable-msg">However, you must provide a payment method (e.g. a credit card), for the monthly subscription charge. Please click the Update Payment Method button to do this now.</p>`
|
|
else
|
|
explanation = `<span>You are currently on the {effective_plan_name} level, thank you!</span>`
|
|
|
|
else
|
|
# free plan situation - not much to go on about
|
|
explanation = `<span>You are currently on the {effective_plan_name} plan.</span>`
|
|
if show_payment_info
|
|
update_payment_btn = `<a className="button-orange update-payment-method" href="/client#/account/paymentHistory" onClick={this.onUpdatePaymentMethod}>UPDATE PAYMENT METHOD</a>`
|
|
if has_pending_subscription
|
|
if this.props.subscription.subscription.plan.plan_code != this.props.subscription.plan_code
|
|
billingAddendum = `<span>You have paid only for the <span className="plan-name">{this.getDisplayNameTier(this.props.subscription.subscription.plan.plan_code)}</span> level for the current billing cycle, so there will be a change to the <span className="plan-name">{this.getDisplayNameTier(this.props.subscription.subscription.pending_subscription.plan.plan_code)}</span> level on the next billing cycle.</span>`
|
|
else
|
|
billingAddendum = `<span>And your plan and billing will switch to the <span className="plan-name">{this.getDisplayNameTier(this.props.subscription.subscription.pending_subscription.plan.plan_code)}</span> level on the next billing cycle.</span>`
|
|
else if cancelled_subscription && this.props.subscription.desired_plan_code == null && this.props.subscription.plan_code != null
|
|
billingAddendum = `<span>However, your cancelled {effective_plan_name} plan is still active until the end of the billing cycle.</span>`# `<span><br/><br/><span>You will be billed a final time at the <span className="plan-name">{this.getDisplayNameTier(this.props.subscription.subscription.plan.plan_code)}</span> at end of this billing cycle.</span></span>`
|
|
else
|
|
billingAddendum = null
|
|
if @props.subscription.subscription_rules.remaining_month_play_time
|
|
remaining_month_play_time = @props.subscription.subscription_rules.remaining_month_play_time
|
|
until_time = new Date()
|
|
until_time = new Date(until_time.getTime() + remaining_month_play_time * 1000)
|
|
#until_time.setSeconds(until_time.getSeconds() + @subscriptionRules.remaining_month_play_time)
|
|
playtime = `<div className="play-time">
|
|
<label>monthly play time remaining:</label>
|
|
<p>You have <span className="playtime">{this.displayTime(remaining_month_play_time)}</span> remaining this month. Only the time you spend in a session with 2 or more people uses your session play time.</p>
|
|
</div>`
|
|
else
|
|
playtime = `<div className="play-time">
|
|
<label>monthly play time remaining:</label>
|
|
<p>You have unlimited play time.</p>
|
|
</div>`
|
|
`<div className="current-subscription">
|
|
<div>
|
|
<h2>Subscription:</h2>
|
|
<p className="explainer">Your JamKazam subscription is currently set to the plan displayed below. To compare the features available for different subscription plans, click the Compare Plans button below. To change your plan, click the "subscription plan" list box below, select a new plan, and then click the Update Plan button below.</p>
|
|
<div className="subscription-plan-and-status">
|
|
<div className="subscription-plan">
|
|
<form id="change-subscription-form" onSubmit={this.onChangeSubmit} >
|
|
<label for="plan_code">subscription plan:</label>
|
|
<div className="subscription-actions">
|
|
{plansJsx}
|
|
<a className="button-grey" onClick={this.comparePlans} target="_blank" href="https://jamkazam.freshdesk.com/support/solutions/articles/66000122535-what-are-jamkazam-s-free-vs-premium-features-">COMPARE PLANS</a>
|
|
<button className={changeClass} onClick={this.onSubmit} type="submit">{update_plan_text}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<div className="effective-subscription">
|
|
<div className="explanation">
|
|
<p>{explanation} {billingAddendum}</p>
|
|
{warning}
|
|
</div>
|
|
{playtime}
|
|
<a className="button-grey" onClick={this.onCancel}>BACK</a>{update_payment_btn}
|
|
</div>
|
|
</div>
|
|
</div>`
|
|
|
|
}) |