initial creation

This commit is contained in:
2025-05-20 11:57:43 -04:00
commit c98b612926
8447 changed files with 1862526 additions and 0 deletions
@@ -0,0 +1,383 @@
// A super basic inflection library to pluralize words.
var pluralize = function (word, count) {
if (count === 1) { return word; }
return word + 's';
};
// Add a delay before executing something to prevent hammering the server.
var typewatch = function () {
var timer = 0;
return function (callback, ms) {
clearTimeout(timer);
return timer = setTimeout(callback, ms);
};
}();
// Format datetimes in multiple ways, depending on which CSS class is set on it.
var momentjsClasses = function () {
var $fromNow = $('.from-now');
var $shortDate = $('.short-date');
$fromNow.each(function (i, e) {
(function updateTime() {
var time = moment($(e).data('datetime'));
$(e).text(time.fromNow());
$(e).attr('title', time.format('MMMM Do YYYY, h:mm:ss a Z'));
setTimeout(updateTime, 1000);
})();
});
$shortDate.each(function (i, e) {
var time = moment($(e).data('datetime'));
$(e).text(time.format('MMM Do YYYY'));
$(e).attr('title', time.format('MMMM Do YYYY, h:mm:ss a Z'));
});
};
// Bulk delete items.
var bulkDelete = function () {
var selectAll = '#select_all';
var checkedItems = '.checkbox-item';
var colheader = '.col-header';
var selectedRow = 'warning';
var updateScope = '#scope';
var bulkActions = '#bulk_actions';
$('body').on('change', checkedItems, function () {
var checkedSelector = checkedItems + ':checked';
var itemCount = $(checkedSelector).length;
var pluralizeItem = pluralize('item', itemCount);
var scopeOptionText = itemCount + ' selected ' + pluralizeItem;
if ($(this).is(':checked')) {
$(this).closest('tr').addClass(selectedRow);
$(colheader).hide();
$(bulkActions).show();
}
else {
$(this).closest('tr').removeClass(selectedRow);
if (itemCount === 0) {
$(bulkActions).hide();
$(colheader).show();
}
}
$(updateScope + ' option:first').text(scopeOptionText);
});
$('body').on('change', selectAll, function () {
var checkedStatus = this.checked;
$(checkedItems).each(function () {
$(this).prop('checked', checkedStatus);
$(this).trigger('change');
});
});
};
// Deal with displaying coupon information.
var coupons = function () {
var durationSelector = '#duration';
var durationInMonths = '#duration-in-months';
var redeemBy = '#redeem_by';
var $duration = $(durationSelector);
var $durationInMonths = $(durationInMonths);
var $redeemBy = $(redeemBy);
$('body').on('change', durationSelector, function () {
if ($duration.val() === 'repeating') {
$durationInMonths.show();
}
else {
$durationInMonths.hide();
}
});
if ($redeemBy.length) {
$redeemBy.datetimepicker({
widgetParent: '.dt',
format: 'YYYY-MM-DD HH:mm:ss',
icons: {
time: 'fa fa-clock-o',
date: 'fa fa-calendar',
up: 'fa fa-arrow-up',
down: 'fa fa-arrow-down',
previous: 'fa fa-chevron-left',
next: 'fa fa-chevron-right',
clear: 'fa fa-trash'
}
});
}
};
// Handling processing payments with Stripe.
var stripe = function (form_id) {
var couponCodeSelector = '#coupon_code';
var $form = $(form_id);
var $couponCode = $(couponCodeSelector);
var $couponCodeStatus = $('#coupon_code_status');
var $stripeKey = $('#stripe_key');
var $paymentErrors = $('.payment-errors');
var $spinner = $('.spinner');
var errors = {
'missing_name': 'You must enter your name.'
};
// This identifies your website in the createToken call below.
if ($stripeKey.val()) {
Stripe.setPublishableKey($stripeKey.val());
}
var stripeResponseHandler = function (status, response) {
$paymentErrors.hide();
if (response.error) {
$spinner.hide();
$form.find('button').prop('disabled', false);
$paymentErrors.text(response.error.message);
$paymentErrors.show();
}
else {
// Token contains id, last 4 digits, and card type.
var token = response.id;
// Insert the token into the form so it gets submit to the server.
var field = '<input type="hidden" id="stripe_token" name="stripe_token" />';
$form.append($(field).val(token));
// Process the payment.
$spinner.show();
$form.get(0).submit();
}
};
var discountType = function (percentOff, amountOff) {
if (percentOff) {
return percentOff + '%';
}
return '$' + amountOff;
};
var discountDuration = function (duration, durationInMonths) {
switch (duration) {
case 'forever':
{
return ' forever';
}
case 'once':
{
return ' first payment';
}
default:
{
return ' for ' + durationInMonths + ' months';
}
}
};
var protectAgainstInvalidCoupon = function (coupon, couponStatus) {
if (couponStatus.is(':visible') &&
!couponStatus.hasClass('alert-success')) {
coupon.select();
return false;
}
return true;
};
var checkCouponCode = function (csrfToken) {
return $.ajax({
type: 'POST',
url: '/subscription/coupon_code',
data: {coupon_code: $(couponCodeSelector).val()},
dataType: 'json',
beforeSend: function (xhr) {
xhr.setRequestHeader('X-CSRFToken', csrfToken);
return $couponCodeStatus.text('')
.removeClass('alert-success alert-warning alert-error').hide();
}
}).done(function (data, status, xhr) {
var code = xhr.responseJSON.data;
var amount = discountType(code.percent_off, code.amount_off) + ' off';
var duration = discountDuration(code.duration, code.duration_in_months);
return $couponCodeStatus.addClass('alert-success')
.text(amount + duration);
}).fail(function (xhr, status, error) {
var status_class = 'alert-error';
if (xhr.status === 404) {
status_class = 'alert-warning';
}
return $couponCodeStatus.addClass(status_class)
.text(xhr.responseJSON.error);
}).always(function (xhr, status, error) {
$couponCodeStatus.show();
return $couponCode.val();
});
};
jQuery(function ($) {
var lookupDelayInMS = 300;
var csrfToken = $('meta[name=csrf-token]').attr('content');
$('body').on('keyup', couponCodeSelector, function () {
if ($couponCode.val().length === 0) {
$couponCodeStatus.hide();
return false;
}
typewatch(function () {
checkCouponCode(csrfToken);
}, lookupDelayInMS);
});
$('body').on('submit', $('form').closest('button'), function () {
if (!protectAgainstInvalidCoupon($couponCode, $couponCodeStatus)) {
return false;
}
$spinner.show();
});
$('body').on('submit', form_id, function () {
var $form = $(this);
var $name = $('#name');
if (!protectAgainstInvalidCoupon($couponCode, $couponCodeStatus)) {
return false;
}
$spinner.show();
$paymentErrors.hide();
// Custom check to make sure their name exists.
if ($name.val().length === 0) {
$paymentErrors.text(errors.missing_name);
$paymentErrors.show();
$spinner.hide();
return false;
}
// Disable the submit button to prevent repeated clicks.
$form.find('button').prop('disabled', true);
Stripe.card.createToken($form, stripeResponseHandler);
// Prevent the form from submitting with the default action.
return false;
});
});
};
// Placing bets.
var bets = function () {
var guessSelector = '#guess';
var wageredSelector = '#wagered';
var recentBetsSelector = '#recent_bets';
var $userCoins = $('#user_coins');
var $outcomeStatus = $('#outcome');
var $spinner = $('.spinner');
var $form = $('#place_bet');
var placeBet = function (csrfToken) {
return $.ajax({
type: 'POST',
url: '/bet/place',
data: {guess: $(guessSelector).val(), wagered: $(wageredSelector).val()},
dataType: 'json',
beforeSend: function (xhr) {
xhr.setRequestHeader('X-CSRFToken', csrfToken);
return $outcomeStatus.text('')
.removeClass('alert-success alert-warning alert-error').hide();
}
}).done(function (data, status, xhr) {
var parsed_data = xhr.responseJSON.data;
var dice_entities = '';
var status_class = '';
var coinsLeft = parseInt($userCoins.text());
$userCoins.text(coinsLeft + parsed_data.net);
if (parsed_data.is_winner) {
status_class = '<i class="fa fa-fw fa-smile-o"></i> Congrats, you won!';
bet_class = 'success';
} else {
status_class = '<i class="fa fa-fw fa-frown-o"></i> You lost, try again!';
bet_class = 'danger';
}
dice_entities += "&#x268" + (parseInt(parsed_data.die_1) - 1) + "; ";
dice_entities += "&#x268" + (parseInt(parsed_data.die_2) - 1) + "; ";
$('#dice').html(dice_entities);
$(recentBetsSelector).show();
var guessCol = '<td>' + parsed_data.guess + '</td>';
var rollCol = '<td>' + parsed_data.roll + '</td>';
var wageredCol = '<td class="text-warning"><i class="fa fa-fw fa-database"></i> ' + parsed_data.wagered + '</td>';
var payoutCol = '<td>' + parseFloat(parsed_data.payout) + 'x</td>';
var netCol = '<td class="text-' + bet_class + '"><i class="fa fa-fw fa-database"></i> ' + parsed_data.net + '</td>';
var recentBet = '<tr>' + guessCol + rollCol + wageredCol + payoutCol + netCol + '</tr>';
var recentBetCount = $(recentBetsSelector + ' tr').length;
$(recentBetsSelector + ' tbody').prepend(recentBet);
if (recentBetCount > 10) {
$(recentBetsSelector + ' tr:last').remove();
}
return $outcomeStatus.addClass('alert alert-info alert-small').html(status_class);
}).fail(function (xhr, status, error) {
var status_class = 'alert-error';
var error_status = 'You are out of coins. You should buy more.';
if (xhr.responseJSON) {
error_status = xhr.responseJSON.error;
} else if (error == 'TOO MANY REQUESTS') {
error_status = 'You have been temporarily rate limited.';
}
return $outcomeStatus.addClass(status_class).text(error_status);
}).always(function (xhr, status, error) {
$spinner.hide();
$form.find('button').prop('disabled', false);
$outcomeStatus.show();
return xhr;
});
};
jQuery(function ($) {
var csrfToken = $('meta[name=csrf-token]').attr('content');
$('body').on('submit', '#place_bet', function () {
$spinner.show();
$form.find('button').prop('disabled', true);
placeBet(csrfToken);
return false;
});
});
};
// Initialize everything when the browser is ready.
$(document).ready(function() {
momentjsClasses();
bulkDelete();
coupons();
stripe('#subscription_form');
stripe('#payment_form');
bets();
});
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long