mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-08 19:34:39 -04:00
Merge pull request #6960 from beganovich/jira-778
Prevent double form submission
This commit is contained in:
commit
d8cc9c1d4d
2
public/js/clients/invoices/payment.js
vendored
2
public/js/clients/invoices/payment.js
vendored
@ -1,2 +1,2 @@
|
|||||||
/*! For license information please see payment.js.LICENSE.txt */
|
/*! For license information please see payment.js.LICENSE.txt */
|
||||||
(()=>{function e(e,t){for(var n=0;n<t.length;n++){var a=t[n];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}var t=function(){function t(e,n){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,t),this.shouldDisplayTerms=e,this.shouldDisplaySignature=n,this.termsAccepted=!1}var n,a,i;return n=t,(a=[{key:"handleMethodSelect",value:function(e){var t=this;document.getElementById("company_gateway_id").value=e.dataset.companyGatewayId,document.getElementById("payment_method_id").value=e.dataset.gatewayTypeId,this.shouldDisplaySignature&&!this.shouldDisplayTerms&&(this.displayTerms(),document.getElementById("accept-terms-button").addEventListener("click",(function(){t.termsAccepted=!0,t.submitForm()}))),!this.shouldDisplaySignature&&this.shouldDisplayTerms&&(this.displaySignature(),document.getElementById("signature-next-step").addEventListener("click",(function(){document.querySelector('input[name="signature"').value=t.signaturePad.toDataURL(),t.submitForm()}))),this.shouldDisplaySignature&&this.shouldDisplayTerms&&(this.displaySignature(),document.getElementById("signature-next-step").addEventListener("click",(function(){t.displayTerms(),document.getElementById("accept-terms-button").addEventListener("click",(function(){document.querySelector('input[name="signature"').value=t.signaturePad.toDataURL(),t.termsAccepted=!0,t.submitForm()}))}))),this.shouldDisplaySignature||this.shouldDisplayTerms||this.submitForm()}},{key:"submitForm",value:function(){document.getElementById("payment-form").submit()}},{key:"displayTerms",value:function(){document.getElementById("displayTermsModal").removeAttribute("style")}},{key:"displaySignature",value:function(){document.getElementById("displaySignatureModal").removeAttribute("style");var e=new SignaturePad(document.getElementById("signature-pad"),{penColor:"rgb(0, 0, 0)"});this.signaturePad=e}},{key:"handle",value:function(){var e=this;document.querySelectorAll(".dropdown-gateway-button").forEach((function(t){t.addEventListener("click",(function(){return e.handleMethodSelect(t)}))}))}}])&&e(n.prototype,a),i&&e(n,i),t}(),n=document.querySelector('meta[name="require-invoice-signature"]').content,a=document.querySelector('meta[name="show-invoice-terms"]').content;new t(Boolean(+n),Boolean(+a)).handle()})();
|
(()=>{function e(e,t){for(var n=0;n<t.length;n++){var a=t[n];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}var t=function(){function t(e,n){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,t),this.shouldDisplayTerms=e,this.shouldDisplaySignature=n,this.termsAccepted=!1,this.submitting=!1}var n,a,i;return n=t,(a=[{key:"handleMethodSelect",value:function(e){var t=this;document.getElementById("company_gateway_id").value=e.dataset.companyGatewayId,document.getElementById("payment_method_id").value=e.dataset.gatewayTypeId,this.shouldDisplaySignature&&!this.shouldDisplayTerms&&(this.displayTerms(),document.getElementById("accept-terms-button").addEventListener("click",(function(){t.termsAccepted=!0,t.submitForm()}))),!this.shouldDisplaySignature&&this.shouldDisplayTerms&&(this.displaySignature(),document.getElementById("signature-next-step").addEventListener("click",(function(){document.querySelector('input[name="signature"').value=t.signaturePad.toDataURL(),t.submitForm()}))),this.shouldDisplaySignature&&this.shouldDisplayTerms&&(this.displaySignature(),document.getElementById("signature-next-step").addEventListener("click",(function(){t.displayTerms(),document.getElementById("accept-terms-button").addEventListener("click",(function(){document.querySelector('input[name="signature"').value=t.signaturePad.toDataURL(),t.termsAccepted=!0,t.submitForm()}))}))),this.shouldDisplaySignature||this.shouldDisplayTerms||this.submitForm()}},{key:"submitForm",value:function(){document.getElementById("payment-form").submit()}},{key:"displayTerms",value:function(){document.getElementById("displayTermsModal").removeAttribute("style")}},{key:"displaySignature",value:function(){document.getElementById("displaySignatureModal").removeAttribute("style");var e=new SignaturePad(document.getElementById("signature-pad"),{penColor:"rgb(0, 0, 0)"});this.signaturePad=e}},{key:"handle",value:function(){var e=this;document.querySelectorAll(".dropdown-gateway-button").forEach((function(t){t.addEventListener("click",(function(){e.submitting||(e.handleMethodSelect(t),e.submitting=!0)}))}))}}])&&e(n.prototype,a),i&&e(n,i),t}(),n=document.querySelector('meta[name="require-invoice-signature"]').content,a=document.querySelector('meta[name="show-invoice-terms"]').content;new t(Boolean(+n),Boolean(+a)).handle()})();
|
@ -4,7 +4,7 @@
|
|||||||
"/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js?id=cfe5de1cf87a0b01568d",
|
"/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js?id=cfe5de1cf87a0b01568d",
|
||||||
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=5e74bc0d346beeb57ee9",
|
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=5e74bc0d346beeb57ee9",
|
||||||
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=6b79265cbb8c963eef19",
|
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=6b79265cbb8c963eef19",
|
||||||
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=5b79f72432f92a85fefa",
|
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=d9132fae12153a6943a6",
|
||||||
"/js/clients/payments/stripe-sofort.js": "/js/clients/payments/stripe-sofort.js?id=926c7b9d1ee48bbf786b",
|
"/js/clients/payments/stripe-sofort.js": "/js/clients/payments/stripe-sofort.js?id=926c7b9d1ee48bbf786b",
|
||||||
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=1e159400d6a5ca4662c1",
|
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=1e159400d6a5ca4662c1",
|
||||||
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=0b47ce36fe20191adb33",
|
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=0b47ce36fe20191adb33",
|
||||||
|
11
resources/js/clients/invoices/payment.js
vendored
11
resources/js/clients/invoices/payment.js
vendored
@ -13,6 +13,7 @@ class Payment {
|
|||||||
this.shouldDisplayTerms = displayTerms;
|
this.shouldDisplayTerms = displayTerms;
|
||||||
this.shouldDisplaySignature = displaySignature;
|
this.shouldDisplaySignature = displaySignature;
|
||||||
this.termsAccepted = false;
|
this.termsAccepted = false;
|
||||||
|
this.submitting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMethodSelect(element) {
|
handleMethodSelect(element) {
|
||||||
@ -95,9 +96,13 @@ class Payment {
|
|||||||
document
|
document
|
||||||
.querySelectorAll(".dropdown-gateway-button")
|
.querySelectorAll(".dropdown-gateway-button")
|
||||||
.forEach(element => {
|
.forEach(element => {
|
||||||
element.addEventListener("click", () =>
|
element.addEventListener("click", () => {
|
||||||
this.handleMethodSelect(element)
|
if (!this.submitting) {
|
||||||
);
|
this.handleMethodSelect(element)
|
||||||
|
|
||||||
|
this.submitting = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
<option>15</option>
|
<option>15</option>
|
||||||
<option>20</option>
|
<option>20</option>
|
||||||
</select>
|
</select>
|
||||||
<button x-on:click="document.getElementById('multiple-downloads').submit()" class="button button-primary bg-primary py-2 ml-2">
|
<button onclick="document.getElementById('multiple-downloads').submit(); setTimeout(() => this.disabled = true, 0); setTimeout(() => this.disabled = false, 5000);" class="button button-primary bg-primary py-2 ml-2">
|
||||||
<span class="hidden md:block">
|
<span class="hidden md:block">
|
||||||
{{ ctrans('texts.download_selected') }}
|
{{ ctrans('texts.download_selected') }}
|
||||||
</span>
|
</span>
|
||||||
|
@ -99,7 +99,7 @@
|
|||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" name="invoices[]" value="{{ $invoice->hashed_id }}">
|
<input type="hidden" name="invoices[]" value="{{ $invoice->hashed_id }}">
|
||||||
<input type="hidden" name="action" value="payment">
|
<input type="hidden" name="action" value="payment">
|
||||||
<button class="px-2 py-1 mr-3 text-xs uppercase button button-primary bg-primary" dusk="pay-now">
|
<button onclick="setTimeout(() => this.disabled = true, 0); return true;" class="px-2 py-1 mr-3 text-xs uppercase button button-primary bg-primary" dusk="pay-now">
|
||||||
{{ ctrans('texts.pay_now') }}
|
{{ ctrans('texts.pay_now') }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<form action="{{ route('client.invoices.bulk') }}" method="post" id="bulkActions">
|
<form action="{{ route('client.invoices.bulk') }}" method="post" id="bulkActions">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="button button-primary bg-primary" name="action" value="download">{{ ctrans('texts.download') }}</button>
|
<button type="submit" onclick="setTimeout(() => this.disabled = true, 0); setTimeout(() => this.disabled = false, 5000); return true;" class="button button-primary bg-primary" name="action" value="download">{{ ctrans('texts.download') }}</button>
|
||||||
|
|
||||||
@if(!empty(auth()->user()->client->service()->getPaymentMethods(0)))
|
@if(!empty(auth()->user()->client->service()->getPaymentMethods(0)))
|
||||||
<button type="submit" class="button button-primary bg-primary" name="action" value="payment">{{ ctrans('texts.pay_now') }}</button>
|
<button onclick="setTimeout(() => this.disabled = true, 0); return true;" type="submit" class="button button-primary bg-primary" name="action" value="payment">{{ ctrans('texts.pay_now') }}</button>
|
||||||
@endif
|
@endif
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
<form action="{{ route('client.payment_methods.destroy', [$payment_method->hashed_id, 'method' => $payment_method->gateway_type->id]) }}" method="post">
|
<form action="{{ route('client.payment_methods.destroy', [$payment_method->hashed_id, 'method' => $payment_method->gateway_type->id]) }}" method="post">
|
||||||
@csrf
|
@csrf
|
||||||
@method('DELETE')
|
@method('DELETE')
|
||||||
<button type="submit" class="button button-danger button-block" dusk="confirm-payment-removal">
|
<button type="submit" onclick="setTimeout(() => this.disabled = true, 0); return true;" class="button button-danger button-block" dusk="confirm-payment-removal">
|
||||||
{{ ctrans('texts.remove') }}
|
{{ ctrans('texts.remove') }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<div class="relative inline-block text-left">
|
<div class="relative inline-block text-left">
|
||||||
<div>
|
<div>
|
||||||
<div class="rounded-md shadow-sm">
|
<div class="rounded-md shadow-sm">
|
||||||
<button type="button" id="approve-button"
|
<button type="button" id="approve-button" onclick="setTimeout(() => this.disabled = true, 0); return true;"
|
||||||
class="inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:ring-blue active:bg-gray-50 active:text-gray-800 transition ease-in-out duration-150">
|
class="inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:ring-blue active:bg-gray-50 active:text-gray-800 transition ease-in-out duration-150">
|
||||||
{{ ctrans('texts.approve') }}
|
{{ ctrans('texts.approve') }}
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,27 +1,30 @@
|
|||||||
<form action="{{ route('client.quotes.bulk') }}" method="post" id="approve-form" />
|
<form action="{{ route('client.quotes.bulk') }}" method="post" id="approve-form" />
|
||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" name="action" value="approve">
|
|
||||||
<input type="hidden" name="process" value="true">
|
|
||||||
<input type="hidden" name="quotes[]" value="{{ $quote->hashed_id }}">
|
|
||||||
<input type="hidden" name="signature">
|
|
||||||
|
|
||||||
<div class="bg-white shadow sm:rounded-lg">
|
<input type="hidden" name="action" value="approve">
|
||||||
<div class="px-4 py-5 sm:p-6">
|
<input type="hidden" name="process" value="true">
|
||||||
<div class="sm:flex sm:items-start sm:justify-between">
|
<input type="hidden" name="quotes[]" value="{{ $quote->hashed_id }}">
|
||||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
<input type="hidden" name="signature">
|
||||||
{{ ctrans('texts.approve') }}
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<div class="mt-5 sm:mt-0 sm:ml-6 sm:flex-shrink-0 sm:flex sm:items-center">
|
<div class="bg-white shadow sm:rounded-lg">
|
||||||
@yield('quote-not-approved-right-side')
|
<div class="px-4 py-5 sm:p-6">
|
||||||
|
<div class="sm:flex sm:items-start sm:justify-between">
|
||||||
|
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||||
|
{{ ctrans('texts.approve') }}
|
||||||
|
</h3>
|
||||||
|
|
||||||
<div class="inline-flex rounded-md shadow-sm">
|
<div class="mt-5 sm:mt-0 sm:ml-6 sm:flex-shrink-0 sm:flex sm:items-center">
|
||||||
<input type="hidden" name="action" value="payment">
|
@yield('quote-not-approved-right-side')
|
||||||
<button type="button" class="button button-primary bg-primary" id="approve-button">{{ ctrans('texts.approve') }}</button>
|
|
||||||
</div>
|
<div class="inline-flex rounded-md shadow-sm">
|
||||||
|
<input type="hidden" name="action" value="payment">
|
||||||
|
<button onclick="setTimeout(() => this.disabled = true, 0); return true;" type="button"
|
||||||
|
class="button button-primary bg-primary"
|
||||||
|
id="approve-button">{{ ctrans('texts.approve') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
@section('meta_title', ctrans('texts.quotes'))
|
@section('meta_title', ctrans('texts.quotes'))
|
||||||
|
|
||||||
@section('header')
|
@section('header')
|
||||||
@if($errors->any())
|
@if ($errors->any())
|
||||||
<div class="alert alert-failure mb-4">
|
<div class="alert alert-failure mb-4">
|
||||||
@foreach($errors->all() as $error)
|
@foreach ($errors->all() as $error)
|
||||||
<p>{{ $error }}</p>
|
<p>{{ $error }}</p>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
@ -15,13 +15,17 @@
|
|||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<form action="{{ route('client.quotes.bulk') }}" method="post" id="bulkActions">
|
<form action="{{ route('client.quotes.bulk') }}" method="post" id="bulkActions">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="button button-primary bg-primary" name="action"
|
<button type="submit"
|
||||||
value="download">{{ ctrans('texts.download') }}</button>
|
onclick="setTimeout(() => this.disabled = true, 0); setTimeout(() => this.disabled = false, 5000); return true;"
|
||||||
<button type="submit" class="button button-primary bg-primary" name="action"
|
class="button button-primary bg-primary" name="action"
|
||||||
value="approve">{{ ctrans('texts.approve') }}</button>
|
value="download">{{ ctrans('texts.download') }}</button>
|
||||||
|
<button type="submit" onclick="setTimeout(() => this.disabled = true, 0); return true;"
|
||||||
|
class="button button-primary bg-primary" name="action"
|
||||||
|
value="approve">{{ ctrans('texts.approve') }}</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col mt-4">
|
<div class="flex flex-col mt-4">
|
||||||
@livewire('quotes-table', ['company' => $company])
|
@livewire('quotes-table', ['company' => $company])
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
<span class="ml-2">{{ ctrans('texts.show_aging') }}</span>
|
<span class="ml-2">{{ ctrans('texts.show_aging') }}</span>
|
||||||
</label> <!-- End show aging checkbox -->
|
</label> <!-- End show aging checkbox -->
|
||||||
</div>
|
</div>
|
||||||
<button id="pdf-download" class="button button-primary bg-primary mt-4 md:mt-0">{{ ctrans('texts.download') }}</button>
|
<button onclick="setTimeout(() => this.disabled = true, 0); setTimeout(() => this.disabled = false, 5000); return true;" id="pdf-download" class="button button-primary bg-primary mt-4 md:mt-0">{{ ctrans('texts.download') }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('portal.ninja2020.components.pdf-viewer', ['url' => route('client.statement.raw')])
|
@include('portal.ninja2020.components.pdf-viewer', ['url' => route('client.statement.raw')])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user