* feat: remove the default email and cobine the periodic digest and the contact email under the Email section * refactor: rename the email_link to contact link and use the contact_email as a default and fallback to the ForemInstance.email * chore: alignment * feat: use the contact_email helper * feat: move the contact_email to the ForemInstance model * feat: use ForemInstance.contact_email instead of the application helper method * removed the application Helper * feat: set the dafault on the contact_email * fix: cypress tests * Update app/lib/constants/settings/general.rb Co-authored-by: Michael Kohl <me@citizen428.net> Co-authored-by: Michael Kohl <me@citizen428.net>
302 lines
10 KiB
Text
302 lines
10 KiB
Text
<% title t("views.credits.new.meta.title") %>
|
|
|
|
<div class="credits-container">
|
|
<div class="credits-banner">
|
|
<h1><%= t("views.credits.new.heading", name: @purchaser.username) %></h1>
|
|
|
|
<% if @organizations %>
|
|
<% @organizations.each do |org| %>
|
|
<% unless @purchaser.id == org.id %>
|
|
<a href="/credits/purchase?organization_id=<%= org.id %>" data-no-instant><%= t("views.credits.new.switch.org", name: org.name) %></a>
|
|
<% end %>
|
|
<% end %>
|
|
<% end %>
|
|
<% unless @purchaser.is_a? User %>
|
|
<a href="/credits/purchase" data-no-instant><%= t("views.credits.new.switch.user") %></a>
|
|
<% end %>
|
|
</div>
|
|
|
|
<% if flash[:error].present? %>
|
|
<div class="crayons-card crayons-card--secondary crayons-notice crayons-notice--danger" role="alert">
|
|
<p><%= flash[:error] %></p>
|
|
</div>
|
|
<% end %>
|
|
|
|
<script src="https://js.stripe.com/v3/"></script>
|
|
|
|
<p class="hook-description">Credits are used for <a href="/listings"><%= community_name %> listings</a> as well as upcoming products and services.</p>
|
|
|
|
<div style="margin-top: 30px; text-align: center">
|
|
<div class="credit-price" data-num="1">
|
|
<div class="credit-amount" data-num="1">1+</div>
|
|
$5/per credit
|
|
</div>
|
|
<div class="credit-price" data-num="10">
|
|
<div class="credit-amount" data-num="10">10+</div>
|
|
$4/per credit</div>
|
|
<div class="credit-price" data-num="100">
|
|
<div class="credit-amount" data-num="100">
|
|
100+
|
|
</div>
|
|
$3/per credit</div>
|
|
<div class="credit-price" data-num="1000">
|
|
<div class="credit-amount" data-num="1000">
|
|
1000+
|
|
</div>
|
|
$2.50/per credit
|
|
</div>
|
|
<br />
|
|
</div>
|
|
<p class="bulk-description"><em>Contact <%= contact_link(additional_info: { subject: "Custom Bulk Pricing/Partnerships" }) %> for custom bulk pricing and partnerships.</em></p>
|
|
<details>
|
|
<summary>
|
|
How many credits does one listing cost?
|
|
</summary>
|
|
<div>
|
|
<p>
|
|
All listings cost <strong>1 credit</strong>, except:
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
<strong>products/tools: 5 credits</strong>
|
|
</li>
|
|
<li>
|
|
<strong>job listings: 25 credits</strong>
|
|
</li>
|
|
</ul>
|
|
<p>
|
|
Buying more credits upfront makes listings more cost-effective.
|
|
</p>
|
|
<p>
|
|
25 credits purchased today costs $100. 25 credits purchased individually will cost $125, etc.
|
|
</p>
|
|
</div>
|
|
</details>
|
|
<details>
|
|
<summary>
|
|
<%= params[:organization_id].present? ? t("views.credits.new.status.subtitle.org", name: @purchaser.name) : t("views.credits.new.status.subtitle.user") %>
|
|
</summary>
|
|
<div>
|
|
<p>
|
|
<% count = @purchaser.credits.where(spent: false).size %>
|
|
<%= params[:organization_id].present? ? t("views.credits.new.status.desc.org", name: @purchaser.name, count: count) : t("views.credits.new.status.desc.user", count: count) %>
|
|
</p>
|
|
</div>
|
|
</details>
|
|
<details>
|
|
<summary>
|
|
<%= t("views.credits.new.how.subtitle") %>
|
|
</summary>
|
|
<div>
|
|
<p>
|
|
<%= t("views.credits.new.how.desc_html") %>
|
|
</p>
|
|
</div>
|
|
</details>
|
|
<%= form_for(@credit) do |f| %>
|
|
<label for="amount-input" class="main-form-label">
|
|
<%= t("views.credits.new.form.amount.label") %>
|
|
</label>
|
|
<div class="amount-wrapper">
|
|
<%= f.number_field :number_to_purchase,
|
|
id: "amount-input",
|
|
placeholder: t("views.credits.new.form.amount.placeholder"), autocomplete: "off",
|
|
min: "0",
|
|
max: "10000000",
|
|
required: true %>
|
|
<div id="calculated-price"></div>
|
|
</div>
|
|
<% if @purchaser.is_a? Organization %>
|
|
<input type="hidden" name="organization_id" value="<%= @purchaser.id %>">
|
|
<% end %>
|
|
<div class="form-row">
|
|
<label for="card-element" class="main-form-label">
|
|
<%= t("views.credits.new.form.method.label") %>
|
|
</label>
|
|
<% if @customer %>
|
|
<div id="cards-wrapper">
|
|
<% @customer.sources.each do |source| %>
|
|
<div class="existing-card">
|
|
<input type="radio" <%= "checked" if source.id == @customer.default_source %>
|
|
name="selected_card" value="<%= source.id %>" id="existing-card-<%= source.id %>" />
|
|
<label for="existing-card-<%= source.id %>">
|
|
<span class="credit-card-component credit-card-component--bold"><%= source.brand %></span>
|
|
<span class="credit-card-component"><%= t("views.credits.new.form.method.number", last: source.last4) %></span>
|
|
<span class="credit-card-component"><%= t("views.credits.new.form.method.exp", mm: source.exp_month, yy: source.exp_year.to_s.last(2)) %></span>
|
|
</label>
|
|
</div>
|
|
<% end %>
|
|
<button id="add-new-card"><%= t("views.credits.new.form.method.add") %></button>
|
|
</div>
|
|
<% else %>
|
|
<div id="card-element">
|
|
<%# A Stripe Element will be inserted here. %>
|
|
</div>
|
|
<% end %>
|
|
<%# Used to display form errors. %>
|
|
<div id="card-errors" role="alert"></div>
|
|
</div>
|
|
<button id="add-credit-card-button" class="credit-card-button"><%= t("views.credits.new.form.submit") %></button>
|
|
<% if @purchaser.is_a? Organization %>
|
|
<p><em><%= t("views.credits.new.form.note_org") %></em></p>
|
|
<% end %>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
function changeSubmitButton(opts) {
|
|
var button = document.getElementById('add-credit-card-button');
|
|
button.disabled = !opts.active;
|
|
button.textContent = opts.text;
|
|
}
|
|
|
|
var form = document.getElementById('new_credit');
|
|
form.onsubmit = function(_event) {
|
|
changeSubmitButton({ text: '<%= t("views.credits.new.form.submitting") %>', active: false })
|
|
}
|
|
|
|
var stripe = Stripe('<%= Settings::General.stripe_publishable_key %>');
|
|
var elements = stripe.elements();
|
|
|
|
<% if current_user.setting.dark_theme? %>
|
|
var style = {
|
|
base: {
|
|
color: 'white',
|
|
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
|
|
fontSmoothing: 'antialiased',
|
|
fontSize: '16px',
|
|
'::placeholder': {
|
|
color: '#d9dee2'
|
|
}
|
|
},
|
|
invalid: {
|
|
color: '#fa755a',
|
|
iconColor: '#fa755a'
|
|
}
|
|
};
|
|
<% else %>
|
|
var style = {
|
|
base: {
|
|
color: '#32325d',
|
|
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
|
|
fontSmoothing: 'antialiased',
|
|
fontSize: '16px',
|
|
'::placeholder': {
|
|
color: '#aab7c4'
|
|
}
|
|
},
|
|
invalid: {
|
|
color: '#fa755a',
|
|
iconColor: '#fa755a'
|
|
}
|
|
};
|
|
<% end %>
|
|
|
|
var card = elements.create('card', {style: style});
|
|
|
|
createCardElement();
|
|
handleNewCardClick();
|
|
handleCreditPriceClick();
|
|
listenForNumberChange();
|
|
function createCardElement() {
|
|
if (document.getElementById("card-element")) {
|
|
card.mount('#card-element');
|
|
|
|
card.addEventListener('change', function(event) {
|
|
var displayError = document.getElementById('card-errors');
|
|
if (event.error) {
|
|
displayError.textContent = event.error.message;
|
|
} else {
|
|
displayError.textContent = '';
|
|
}
|
|
});
|
|
var form = document.getElementById('new_credit');
|
|
form.addEventListener('submit', function(event) {
|
|
event.preventDefault();
|
|
|
|
stripe.createToken(card).then(function(result) {
|
|
if (result.error) {
|
|
// Inform the user if there was an error.
|
|
changeSubmitButton({ text: '<%= t("views.credits.new.form.submit") %>', active: true });
|
|
var errorElement = document.getElementById('card-errors');
|
|
errorElement.textContent = result.error.message;
|
|
} else {
|
|
// Send the token to your server.
|
|
stripeTokenHandler(result.token);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
function handleNewCardClick() {
|
|
if (!document.getElementById('add-new-card')) {
|
|
return
|
|
}
|
|
document.getElementById("add-new-card").onclick = function(e) {
|
|
e.preventDefault();
|
|
document.getElementById("cards-wrapper").innerHTML = '<div id="card-element"></div>';
|
|
createCardElement();
|
|
}
|
|
}
|
|
|
|
// Handle form submission.
|
|
|
|
// Submit the form with the token ID.
|
|
function stripeTokenHandler(token) {
|
|
// Insert the token ID into the form so it gets submitted to the server
|
|
var form = document.getElementById('new_credit');
|
|
var hiddenInput = document.createElement('input');
|
|
hiddenInput.setAttribute('type', 'hidden');
|
|
hiddenInput.setAttribute('name', 'stripe_token');
|
|
hiddenInput.setAttribute('value', token.id);
|
|
form.appendChild(hiddenInput);
|
|
|
|
// Submit the form
|
|
form.submit();
|
|
}
|
|
|
|
function getAmount(multiple) {
|
|
var value = document.getElementById('amount-input').value
|
|
var pricePer = 0;
|
|
var saleValue = 0;
|
|
if (value < 10) {
|
|
pricePer = 5;
|
|
} else if (value < 100) {
|
|
pricePer = 4
|
|
} else if (value < 1000) {
|
|
pricePer = 3
|
|
} else {
|
|
pricePer = 2.5;
|
|
}
|
|
saleValue = value * pricePer * multiple
|
|
return {value: saleValue, pricePer: pricePer };
|
|
}
|
|
function handleCreditPriceClick() {
|
|
var els = document.getElementsByClassName('credit-price')
|
|
for(i = 0; i < els.length; i++) {
|
|
els[i].onclick = function(e) {
|
|
document.getElementById("amount-input").value = e.target.dataset.num;
|
|
calculatePriceAndShow();
|
|
}
|
|
}
|
|
}
|
|
function listenForNumberChange() {
|
|
document.getElementById("amount-input").addEventListener("keydown",function (e) {
|
|
(
|
|
(e.keyCode >= 48 && e.keyCode <= 57) || // Keyboard 0-9 Keycode is 48 to 57
|
|
(e.keyCode >= 96 && e.keyCode <= 105) || //Keypad 0-9 Keycode is 96 to 105
|
|
(e.keyCode == 8) //Allow backspace
|
|
)?
|
|
calculatePriceAndShow():
|
|
e.preventDefault();
|
|
});
|
|
}
|
|
|
|
function calculatePriceAndShow() {
|
|
setTimeout(function(){
|
|
document.getElementById("calculated-price").innerHTML = '$'+getAmount(1.0)['value'] + ' ($'+getAmount(1.0)['pricePer']+'/each)';
|
|
}, 100)
|
|
}
|
|
|
|
</script>
|