Fix #547 -- Switch to Stripe Elements

This commit is contained in:
Raphael Michel
2017-07-10 20:00:03 +02:00
parent c70301572c
commit 687ce29366
4 changed files with 124 additions and 143 deletions

View File

@@ -1,115 +1,97 @@
/*global $, stripe_pubkey, stripe_loadingmessage, gettext */
'use strict';
var Stripe = null;
var pretixstripe = {
'validate_number': function () {
var numb = $("#stripe_number").val();
$(".stripe-number").addClass("has-feedback");
if (Stripe.card.validateCardNumber(numb)) {
$(".stripe-number").addClass("has-success").removeClass("has-error");
$(".stripe-number .form-control-feedback").addClass("fa-check")
.removeClass("fa-remove").removeClass("sr-only");
} else {
$(".stripe-number").removeClass("has-success").addClass("has-error");
$(".stripe-number .form-control-feedback").addClass("fa-remove")
.removeClass("fa-ok").removeClass("sr-only");
}
},
'validate_expire': function () {
var month = $("#stripe_exp_month").val();
var year = $("#stripe_exp_year").val();
$(".stripe-exp").addClass("has-feedback");
if (Stripe.card.validateExpiry(month, year)) {
$(".stripe-exp").addClass("has-success").removeClass("has-error");
$(".stripe-exp .form-control-feedback").addClass("fa-check")
.removeClass("fa-remove").removeClass("sr-only");
} else {
$(".stripe-exp").removeClass("has-success").addClass("has-error");
$(".stripe-exp .form-control-feedback").addClass("fa-remove")
.removeClass("fa-ok").removeClass("sr-only");
}
},
'validate_cvc': function () {
var cvc = $("#stripe_cvc").val();
$(".stripe-cvc").addClass("has-feedback");
if (Stripe.card.validateCVC(cvc)) {
$(".stripe-cvc").addClass("has-success").removeClass("has-error");
$(".stripe-cvc .form-control-feedback").addClass("fa-check")
.removeClass("fa-remove").removeClass("sr-only");
} else {
$(".stripe-cvc").removeClass("has-success").addClass("has-error");
$(".stripe-cvc .form-control-feedback").addClass("fa-remove")
.removeClass("fa-ok").removeClass("sr-only");
}
},
stripe: null,
elements: null,
card: null,
'request': function () {
waitingDialog.show(gettext("Contacting Stripe …"));
$(".stripe-errors").hide();
Stripe.card.createToken(
{
number: $('#stripe_number').val(),
cvc: $('#stripe_cvc').val(),
exp_month: $('#stripe_exp_month').val(),
exp_year: $('#stripe_exp_year').val(),
name: $('#stripe_name').val()
},
pretixstripe.response
);
},
'response': function (status, response) {
var $form = $("#stripe_number").parents("form");
waitingDialog.hide();
if (response.error) {
$(".stripe-errors").stop().hide().removeClass("sr-only");
$(".stripe-errors").html("<div class='alert alert-danger'>" + response.error.message + "</div>");
$(".stripe-errors").slideDown();
} else {
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$("#stripe_token").val(token);
$("#stripe_card_brand").val(response.card.brand);
$("#stripe_card_last4").val(response.card.last4);
// and submit
$form.get(0).submit();
}
pretixstripe.stripe.createToken(pretixstripe.card).then(function (result) {
waitingDialog.hide();
if (result.error) {
$(".stripe-errors").stop().hide().removeClass("sr-only");
$(".stripe-errors").html("<div class='alert alert-danger'>" + result.error.message + "</div>");
$(".stripe-errors").slideDown();
} else {
var $form = $("#stripe_token").closest("form");
// Insert the token into the form so it gets submitted to the server
$("#stripe_token").val(result.token.id);
$("#stripe_card_brand").val(result.token.card.brand);
$("#stripe_card_last4").val(result.token.card.last4);
// and submit
$form.get(0).submit();
}
});
},
'load': function () {
$.ajax(
{
url: 'https://js.stripe.com/v2/',
url: 'https://js.stripe.com/v3/',
dataType: 'script',
success: function () {
Stripe.setPublishableKey($.trim($("#stripe_pubkey").html()));
pretixstripe.stripe = Stripe($.trim($("#stripe_pubkey").html()));
pretixstripe.elements = pretixstripe.stripe.elements();
pretixstripe.card = pretixstripe.elements.create('card', {
'style': {
'base': {
'fontFamily': '"Open Sans","OpenSans","Helvetica Neue",Helvetica,Arial,sans-serif',
'fontSize': '14px',
'color': '#555555',
'lineHeight': '1.42857',
'border': '1px solid #ccc',
'::placeholder': {
color: 'rgba(0,0,0,0.4)',
},
},
'invalid': {
'color': 'red',
},
},
classes: {
focus: 'is-focused',
invalid: 'has-error',
}
});
pretixstripe.card.mount("#stripe-card");
}
}
);
}
};
$(function () {
if (!$("#stripe_number").length) // Not on the checkout page
if (!$("#stripe-card").length) // Not on the checkout page
return;
if ($("input[name=payment][value=stripe]").is(':checked') || $(".payment-redo-form").length) {
pretixstripe.load();
} else {
$("input[name=payment]").change(function() {
$("input[name=payment]").change(function () {
if ($(this).val() == 'stripe') {
pretixstripe.load();
}
})
}
// Stripe.setPublishableKey('{{ settings.publishable_key }}');
// <script type="text/javascript" src=""></script>
$("#stripe_other_card").click(
function (e) {
$("#stripe_token").val("");
$("#stripe-current-card").slideUp();
$("#stripe-card").slideDown();
pretixstripe.start();
e.preventDefault();
return false;
}
);
$("#stripe_number").change(pretixstripe.validate_number).keydown(pretixstripe.validate_number)
.keyup(pretixstripe.validate_number);
$(".stripe-exp input").change(pretixstripe.validate_expire).keydown(pretixstripe.validate_expire)
.keyup(pretixstripe.validate_expire)
$("#stripe_cvc").change(pretixstripe.validate_cvc).keydown(pretixstripe.validate_cvc)
.keyup(pretixstripe.validate_cvc)
$("#stripe_number").parents("form").submit(
if ($("#stripe-current-card").length) {
$("#stripe-card").hide();
}
$("#stripe-card").parents("form").submit(
function () {
if (($("input[name=payment][value=stripe]").prop('checked') || $("input[name=payment]").length === 0)
&& $("#stripe_token").val() == "") {

View File

@@ -9,56 +9,40 @@
{% trans "For a credit card payment, please turn on JavaScript." %}
</div>
</noscript>
<div class="form-group stripe-number">
<label class="control-label col-sm-2">
{% trans "Credit card number" %}
</label>
<div class="col-sm-4">
<input type="text" id="stripe_number" class="form-control" placeholder="4242 4242 4242 4242">
<span class="fa form-control-feedback sr-only"></span>
{% if request.session.payment_stripe_token %}
<div id="stripe-current-card">
<p>{% blocktrans trimmed %}
You already entered a card number that we will use to charge the payment amount.
{% endblocktrans %}</p>
<dl class="dl-horizontal">
<dt>{% trans "Card type" %}</dt>
<dd id="stripe_card_brand_display">{{ request.session.payment_stripe_brand }}</dd>
<dt>{% trans "Card number" %}</dt>
<dd>
**** **** ****
<span id="stripe_card_last4_display">{{ request.session.payment_stripe_last4 }}</span>
<button class="btn btn-xs btn-default" id="stripe_other_card" type="button">
{% trans "Use a different card" %}
</button>
</dd>
</dl>
</div>
{% endif %}
<div id="stripe-card" class="form-control">
<!-- a Stripe Element will be inserted here. -->
</div>
<div class="form-group stripe-exp">
<label class="control-label col-sm-2">
{% trans "Expiration date" %}
</label>
<div class="col-sm-2">
<input type="number" min="1" max="12" id="stripe_exp_month" class="form-control" placeholder=
"{% trans "Month" %}">
<span class="fa form-control-feedback sr-only"></span>
</div>
<div class="col-sm-2">
<input type="number" min="{% now "Y" %}" id="stripe_exp_year" class="form-control" placeholder=
"{% trans "Year" %}">
<span class="fa form-control-feedback sr-only"></span>
</div>
</div>
<div class="form-group stripe-cvc">
<label class="control-label col-sm-2">
{% trans "Security code (CVC)" %}
</label>
<div class="col-sm-2">
<input type="text" maxlength="3" id="stripe_cvc" class="form-control" placeholder=
"{% trans "123" %}">
<span class="fa form-control-feedback sr-only"></span>
</div>
</div>
<div class="form-group stripe-name">
<label class="control-label col-sm-2">
{% trans "Cardholder name" %}
</label>
<div class="col-sm-4">
<input type="text" id="stripe_name" class="form-control">
</div>
</div>
<p>
<em>{% blocktrans trimmed %}
<p class="help-block">
{% blocktrans trimmed %}
Your payment will be processed by Stripe, Inc. Your credit card data will be transmitted directly to
Stripe and never touches our servers.
{% endblocktrans %}</em>
<input type="hidden" name="stripe_token" value="" id="stripe_token" />
<input type="hidden" name="stripe_card_last4" value="" id="stripe_card_last4" />
<input type="hidden" name="stripe_card_brand" value="" id="stripe_card_brand" />
{% endblocktrans %}
<input type="hidden" name="stripe_token" value="{{ request.session.payment_stripe_token }}" id="stripe_token"/>
<input type="hidden" name="stripe_card_last4" value="{{ request.session.payment_stripe_last4 }}"
id="stripe_card_last4"/>
<input type="hidden" name="stripe_card_brand" value="{{ request.session.payment_stripe_brand }}"
id="stripe_card_brand"/>
</p>
</div>

View File

@@ -30,11 +30,11 @@
{% endblocktrans %}
</p>
{% endif %}
<p>
<em>{% blocktrans trimmed %}
<p class="help-block">
{% blocktrans trimmed %}
Your payment will be processed by Stripe, Inc. Your credit card data will be transmitted directly to
Stripe and never touches our servers.
{% endblocktrans %}</em>
{% endblocktrans %}
</p>
<input type="hidden" name="stripe_token" value="{{ request.session.payment_stripe_token }}" id="stripe_token"/>
<input type="hidden" name="stripe_card_last4" value="{{ request.session.payment_stripe_last4 }}"

View File

@@ -1,16 +1,31 @@
.panel-title .radio {
margin-left: 20px;
margin-left: 20px;
}
.form-control + .form-control-feedback {
/* Fix for https://github.com/FortAwesome/Font-Awesome/issues/4313 */
position: absolute;
top: 0;
right: 0;
z-index: 2; // Ensure icon is above input groups
display: block;
width: $input-height-base;
height: $input-height-base;
line-height: $input-height-base;
text-align: center;
pointer-events: none;
}
/* Fix for https://github.com/FortAwesome/Font-Awesome/issues/4313 */
position: absolute;
top: 0;
right: 0;
z-index: 2; // Ensure icon is above input groups
display: block;
width: $input-height-base;
height: $input-height-base;
line-height: $input-height-base;
text-align: center;
pointer-events: none;
}
.form-control.is-focused {
@extend .form-control:focus;
}
.form-control.has-error {
border-color: $state-danger-text;
@include box-shadow(inset 0 1px 1px rgba(0, 0, 0, .075)); // Redeclare so transitions work
&:focus, &.is-focused {
border-color: darken($state-danger-text, 10%);
$shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px lighten($state-danger-text, 20%);
@include box-shadow($shadow);
}
}