mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #8069 from turbo124/v5-develop
OTP for subscriptions
This commit is contained in:
commit
4e793c7bea
@ -17,6 +17,7 @@ use App\Jobs\Mail\NinjaMailerJob;
|
|||||||
use App\Jobs\Mail\NinjaMailerObject;
|
use App\Jobs\Mail\NinjaMailerObject;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Mail\ContactPasswordlessLogin;
|
use App\Mail\ContactPasswordlessLogin;
|
||||||
|
use App\Mail\Subscription\OtpCode;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
@ -191,9 +192,9 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
public $discount;
|
public $discount;
|
||||||
public $sub_total;
|
public $sub_total;
|
||||||
public $authenticated = false;
|
public $authenticated = false;
|
||||||
public $otp;
|
|
||||||
public $login;
|
public $login;
|
||||||
public $value;
|
public $float_amount_total;
|
||||||
|
public $payment_started = false;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
@ -201,10 +202,20 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
|
|
||||||
$this->discount = 0;
|
$this->discount = 0;
|
||||||
$this->sub_total = 0;
|
$this->sub_total = 0;
|
||||||
|
$this->float_amount_total = 0;
|
||||||
|
|
||||||
$this->data = [];
|
$this->data = [];
|
||||||
|
|
||||||
$this->price = $this->subscription->price;
|
$this->price = $this->subscription->price; // ?
|
||||||
|
|
||||||
|
$this->recurring_products = $this->subscription->service()->recurring_products();
|
||||||
|
$this->products = $this->subscription->service()->products();
|
||||||
|
$this->optional_recurring_products = $this->subscription->service()->optional_recurring_products();
|
||||||
|
$this->optional_products = $this->subscription->service()->optional_products();
|
||||||
|
|
||||||
|
$this->bundle = collect();
|
||||||
|
|
||||||
|
//every thing below is redundant
|
||||||
|
|
||||||
if (request()->query('coupon')) {
|
if (request()->query('coupon')) {
|
||||||
$this->coupon = request()->query('coupon');
|
$this->coupon = request()->query('coupon');
|
||||||
@ -214,13 +225,6 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
$this->price = $this->subscription->promo_price;
|
$this->price = $this->subscription->promo_price;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->recurring_products = $this->subscription->service()->recurring_products();
|
|
||||||
$this->products = $this->subscription->service()->products();
|
|
||||||
$this->optional_recurring_products = $this->subscription->service()->optional_recurring_products();
|
|
||||||
$this->optional_products = $this->subscription->service()->optional_products();
|
|
||||||
|
|
||||||
$this->bundle = collect();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loginValidation()
|
public function loginValidation()
|
||||||
@ -229,12 +233,19 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
$this->resetValidation('login');
|
$this->resetValidation('login');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleLogin()
|
public function handleLogin($user_code)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
$this->resetErrorBag('login');
|
||||||
|
$this->resetValidation('login');
|
||||||
|
|
||||||
$code = Cache::get("subscriptions:otp:{$this->email}");
|
$code = Cache::get("subscriptions:otp:{$this->email}");
|
||||||
|
|
||||||
$this->validateOnly('login', ['login' => ['required',Rule::in([$code])]], ['login' => ctrans('texts.invalid_code')]);
|
if($user_code != $code){
|
||||||
|
$errors = $this->getErrorBag();
|
||||||
|
$errors->add('login', ctrans('texts.invalid_code'));
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
$contact = ClientContact::where('email', $this->email)->first();
|
$contact = ClientContact::where('email', $this->email)->first();
|
||||||
|
|
||||||
@ -243,10 +254,23 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
$this->contact = $contact;
|
$this->contact = $contact;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
$this->createClientContact();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->authenticated = true;
|
||||||
|
|
||||||
|
$this->getPaymentMethods();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showClientRequiredFields()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resetEmail()
|
||||||
|
{
|
||||||
|
$this->email = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleEmail()
|
public function handleEmail()
|
||||||
@ -259,8 +283,25 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
|
|
||||||
Cache::put($email_hash, $rand, 120);
|
Cache::put($email_hash, $rand, 120);
|
||||||
|
|
||||||
|
$this->emailOtpCode($rand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function emailOtpCode($code)
|
||||||
|
{
|
||||||
|
|
||||||
|
$cc = new ClientContact();
|
||||||
|
$cc->email = $this->email;
|
||||||
|
|
||||||
|
$nmo = new NinjaMailerObject;
|
||||||
|
$nmo->mailable = new OtpCode($this->subscription->company, $this->contact, $code);
|
||||||
|
$nmo->company = $this->subscription->company;
|
||||||
|
$nmo->settings = $this->subscription->company->settings;
|
||||||
|
$nmo->to_user = $cc;
|
||||||
|
NinjaMailerJob::dispatch($nmo);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a coupon being entered into the checkout
|
* Handle a coupon being entered into the checkout
|
||||||
*/
|
*/
|
||||||
@ -383,6 +424,7 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
|
|
||||||
$this->total = Number::formatMoney(($this->bundle->sum('total') - $discount), $this->subscription->company);
|
$this->total = Number::formatMoney(($this->bundle->sum('total') - $discount), $this->subscription->company);
|
||||||
|
|
||||||
|
$this->float_amount_total = ($this->bundle->sum('total') - $discount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -411,9 +453,9 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
$this->contact = $client->fresh()->contacts()->first();
|
$this->contact = $client->fresh()->contacts()->first();
|
||||||
Auth::guard('contact')->loginUsingId($this->contact->id, true);
|
Auth::guard('contact')->loginUsingId($this->contact->id, true);
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public function updated($propertyName)
|
public function updated($propertyName)
|
||||||
{
|
{
|
||||||
@ -424,6 +466,101 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetching payment methods from the client.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
protected function getPaymentMethods(): self
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->methods = $this->contact->client->service()->getPaymentMethods($this->float_amount_total);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Middle method between selecting payment method &
|
||||||
|
* submitting the from to the backend.
|
||||||
|
*
|
||||||
|
* @param $company_gateway_id
|
||||||
|
* @param $gateway_type_id
|
||||||
|
*/
|
||||||
|
public function handleMethodSelectingEvent($company_gateway_id, $gateway_type_id)
|
||||||
|
{
|
||||||
|
$this->company_gateway_id = $company_gateway_id;
|
||||||
|
$this->payment_method_id = $gateway_type_id;
|
||||||
|
|
||||||
|
$this->handleBeforePaymentEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to handle events before payments.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handleBeforePaymentEvents() :void
|
||||||
|
{
|
||||||
|
$this->payment_started = true;
|
||||||
|
|
||||||
|
// $data = [
|
||||||
|
// 'client_id' => $this->contact->client->id,
|
||||||
|
// 'date' => now()->format('Y-m-d'),
|
||||||
|
// 'invitations' => [[
|
||||||
|
// 'key' => '',
|
||||||
|
// 'client_contact_id' => $this->contact->hashed_id,
|
||||||
|
// ]],
|
||||||
|
// 'user_input_promo_code' => $this->coupon,
|
||||||
|
// 'coupon' => empty($this->subscription->promo_code) ? '' : $this->coupon,
|
||||||
|
// // 'quantity' => $this->quantity,
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// $is_eligible = $this->subscription->service()->isEligible($this->contact);
|
||||||
|
|
||||||
|
// if (is_array($is_eligible) && $is_eligible['message'] != 'Success') {
|
||||||
|
// $this->steps['not_eligible'] = true;
|
||||||
|
// $this->steps['not_eligible_message'] = $is_eligible['message'];
|
||||||
|
// $this->steps['show_loading_bar'] = false;
|
||||||
|
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $this->invoice = $this->subscription
|
||||||
|
// ->service()
|
||||||
|
// ->createInvoice($data, $this->quantity)
|
||||||
|
// ->service()
|
||||||
|
// ->markSent()
|
||||||
|
// ->fillDefaults()
|
||||||
|
// ->adjustInventory()
|
||||||
|
// ->save();
|
||||||
|
|
||||||
|
// Cache::put($this->hash, [
|
||||||
|
// 'subscription_id' => $this->subscription->id,
|
||||||
|
// 'email' => $this->email ?? $this->contact->email,
|
||||||
|
// 'client_id' => $this->contact->client->id,
|
||||||
|
// 'invoice_id' => $this->invoice->id,
|
||||||
|
// 'context' => 'purchase',
|
||||||
|
// 'campaign' => $this->campaign,
|
||||||
|
// ], now()->addMinutes(60));
|
||||||
|
|
||||||
|
$this->emit('beforePaymentEventsCompleted');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
$rules = [
|
$rules = [
|
||||||
@ -445,39 +582,39 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Handle user authentication
|
// * Handle user authentication
|
||||||
*
|
// *
|
||||||
* @return $this|bool|void
|
// * @return $this|bool|void
|
||||||
*/
|
// */
|
||||||
public function authenticate()
|
// public function authenticate()
|
||||||
{
|
// {
|
||||||
$this->validate();
|
// $this->validate();
|
||||||
|
|
||||||
$contact = ClientContact::where('email', $this->email)
|
// $contact = ClientContact::where('email', $this->email)
|
||||||
->where('company_id', $this->subscription->company_id)
|
// ->where('company_id', $this->subscription->company_id)
|
||||||
->first();
|
// ->first();
|
||||||
|
|
||||||
if ($contact && $this->steps['existing_user'] === false) {
|
// if ($contact && $this->steps['existing_user'] === false) {
|
||||||
return $this->steps['existing_user'] = true;
|
// return $this->steps['existing_user'] = true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if ($contact && $this->steps['existing_user']) {
|
// if ($contact && $this->steps['existing_user']) {
|
||||||
$attempt = Auth::guard('contact')->attempt(['email' => $this->email, 'password' => $this->password, 'company_id' => $this->subscription->company_id]);
|
// $attempt = Auth::guard('contact')->attempt(['email' => $this->email, 'password' => $this->password, 'company_id' => $this->subscription->company_id]);
|
||||||
|
|
||||||
return $attempt
|
// return $attempt
|
||||||
? $this->getPaymentMethods($contact)
|
// ? $this->getPaymentMethods($contact)
|
||||||
: session()->flash('message', 'These credentials do not match our records.');
|
// : session()->flash('message', 'These credentials do not match our records.');
|
||||||
}
|
// }
|
||||||
|
|
||||||
$this->steps['existing_user'] = false;
|
// $this->steps['existing_user'] = false;
|
||||||
|
|
||||||
$contact = $this->createBlankClient();
|
// $contact = $this->createBlankClient();
|
||||||
|
|
||||||
if ($contact && $contact instanceof ClientContact) {
|
// if ($contact && $contact instanceof ClientContact) {
|
||||||
$this->getPaymentMethods($contact);
|
// $this->getPaymentMethods($contact);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -553,104 +690,7 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
return $client->fresh()->contacts->first();
|
return $client->fresh()->contacts->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetching payment methods from the client.
|
|
||||||
*
|
|
||||||
* @param ClientContact $contact
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
protected function getPaymentMethods(ClientContact $contact): self
|
|
||||||
{
|
|
||||||
Auth::guard('contact')->loginUsingId($contact->id, true);
|
|
||||||
|
|
||||||
$this->contact = $contact;
|
|
||||||
|
|
||||||
if ($this->subscription->trial_enabled) {
|
|
||||||
$this->heading_text = ctrans('texts.plan_trial');
|
|
||||||
$this->steps['show_start_trial'] = true;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((int)$this->price == 0)
|
|
||||||
$this->steps['payment_required'] = false;
|
|
||||||
else
|
|
||||||
$this->steps['fetched_payment_methods'] = true;
|
|
||||||
|
|
||||||
$this->methods = $contact->client->service()->getPaymentMethods($this->price);
|
|
||||||
|
|
||||||
$this->heading_text = ctrans('texts.payment_methods');
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Middle method between selecting payment method &
|
|
||||||
* submitting the from to the backend.
|
|
||||||
*
|
|
||||||
* @param $company_gateway_id
|
|
||||||
* @param $gateway_type_id
|
|
||||||
*/
|
|
||||||
public function handleMethodSelectingEvent($company_gateway_id, $gateway_type_id)
|
|
||||||
{
|
|
||||||
$this->company_gateway_id = $company_gateway_id;
|
|
||||||
$this->payment_method_id = $gateway_type_id;
|
|
||||||
|
|
||||||
$this->handleBeforePaymentEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to handle events before payments.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function handleBeforePaymentEvents()
|
|
||||||
{
|
|
||||||
$this->steps['started_payment'] = true;
|
|
||||||
$this->steps['show_loading_bar'] = true;
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'client_id' => $this->contact->client->id,
|
|
||||||
'date' => now()->format('Y-m-d'),
|
|
||||||
'invitations' => [[
|
|
||||||
'key' => '',
|
|
||||||
'client_contact_id' => $this->contact->hashed_id,
|
|
||||||
]],
|
|
||||||
'user_input_promo_code' => $this->coupon,
|
|
||||||
'coupon' => empty($this->subscription->promo_code) ? '' : $this->coupon,
|
|
||||||
// 'quantity' => $this->quantity,
|
|
||||||
];
|
|
||||||
|
|
||||||
$is_eligible = $this->subscription->service()->isEligible($this->contact);
|
|
||||||
|
|
||||||
if (is_array($is_eligible) && $is_eligible['message'] != 'Success') {
|
|
||||||
$this->steps['not_eligible'] = true;
|
|
||||||
$this->steps['not_eligible_message'] = $is_eligible['message'];
|
|
||||||
$this->steps['show_loading_bar'] = false;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->invoice = $this->subscription
|
|
||||||
->service()
|
|
||||||
->createInvoice($data, $this->quantity)
|
|
||||||
->service()
|
|
||||||
->markSent()
|
|
||||||
->fillDefaults()
|
|
||||||
->adjustInventory()
|
|
||||||
->save();
|
|
||||||
|
|
||||||
Cache::put($this->hash, [
|
|
||||||
'subscription_id' => $this->subscription->id,
|
|
||||||
'email' => $this->email ?? $this->contact->email,
|
|
||||||
'client_id' => $this->contact->client->id,
|
|
||||||
'invoice_id' => $this->invoice->id,
|
|
||||||
'context' => 'purchase',
|
|
||||||
'campaign' => $this->campaign,
|
|
||||||
], now()->addMinutes(60));
|
|
||||||
|
|
||||||
$this->emit('beforePaymentEventsCompleted');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Proxy method for starting the trial.
|
* Proxy method for starting the trial.
|
||||||
|
@ -28,7 +28,6 @@ class GenericReportRequest extends Request
|
|||||||
|
|
||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
nlog($this->date_range);
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'date_range' => 'bail|required|string',
|
'date_range' => 'bail|required|string',
|
||||||
|
63
app/Mail/Subscription/OtpCode.php
Normal file
63
app/Mail/Subscription/OtpCode.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Mail\Subscription;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
|
||||||
|
class OtpCode extends Mailable
|
||||||
|
{
|
||||||
|
// use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
public $contact;
|
||||||
|
|
||||||
|
public $code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($company, $contact, $code)
|
||||||
|
{
|
||||||
|
$this->company = $company;
|
||||||
|
$this->contact = $contact;
|
||||||
|
$this->code = $code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the message.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function build()
|
||||||
|
{
|
||||||
|
App::setLocale($this->company->locale());
|
||||||
|
|
||||||
|
return $this->from(config('mail.from.address'), config('mail.from.name'))
|
||||||
|
->subject(ctrans('texts.otp_code_subject'))
|
||||||
|
->text('email.admin.generic_text')
|
||||||
|
->view('email.admin.generic')
|
||||||
|
->with([
|
||||||
|
'settings' => $this->company->settings,
|
||||||
|
'logo' => $this->company->present()->logo(),
|
||||||
|
'title' => ctrans('texts.otp_code_subject'),
|
||||||
|
'content' => ctrans('texts.otp_code_body', ['code' => $this->code]),
|
||||||
|
'whitelabel' => $this->company->account->isPaid(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -11,8 +11,6 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use function Symfony\Component\String\s;
|
|
||||||
|
|
||||||
class GatewayType extends StaticModel
|
class GatewayType extends StaticModel
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
@ -79,7 +79,6 @@ class Charge
|
|||||||
'payment_method' => $cgt->token,
|
'payment_method' => $cgt->token,
|
||||||
'customer' => $cgt->gateway_customer_reference,
|
'customer' => $cgt->gateway_customer_reference,
|
||||||
'confirm' => true,
|
'confirm' => true,
|
||||||
// 'off_session' => true,
|
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
'metadata' => [
|
'metadata' => [
|
||||||
'payment_hash' => $payment_hash->hash,
|
'payment_hash' => $payment_hash->hash,
|
||||||
|
@ -4895,7 +4895,9 @@ $LANG = array(
|
|||||||
'delete_bank_account' => 'Delete Bank Account',
|
'delete_bank_account' => 'Delete Bank Account',
|
||||||
'archive_transaction' => 'Archive Transaction',
|
'archive_transaction' => 'Archive Transaction',
|
||||||
'delete_transaction' => 'Delete Transaction',
|
'delete_transaction' => 'Delete Transaction',
|
||||||
'otp_code_message' => 'Enter the code emailed.'
|
'otp_code_message' => 'Enter the code emailed.',
|
||||||
|
'otp_code_subject' => 'Your one time passcode code',
|
||||||
|
'otp_code_body' => 'Your one time passcode is :code',
|
||||||
);
|
);
|
||||||
|
|
||||||
return $LANG;
|
return $LANG;
|
||||||
|
@ -231,8 +231,42 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if($authenticated)
|
@if($authenticated)
|
||||||
<button class="bg-white font-semibold hover:bg-gray-600 py-3 text-sm text-blue-500 uppercase w-full">Checkout</button>
|
<div class="mx-auto text-center mt-20 content-center">
|
||||||
@else
|
<h2 class="text-2xl font-bold tracking-wide border-b-2 pb-4">{{ $heading_text ?? ctrans('texts.checkout') }}</h2>
|
||||||
|
@if (session()->has('message'))
|
||||||
|
@component('portal.ninja2020.components.message')
|
||||||
|
{{ session('message') }}
|
||||||
|
@endcomponent
|
||||||
|
@endif
|
||||||
|
@if(count($methods) > 0 && !$payment_started)
|
||||||
|
<div class="mt-4">
|
||||||
|
@foreach($methods as $method)
|
||||||
|
<button
|
||||||
|
wire:click="handleMethodSelectingEvent('{{ $method['company_gateway_id'] }}', '{{ $method['gateway_type_id'] }}')"
|
||||||
|
class="relative -ml-px inline-flex items-center space-x-2 rounded border border-gray-300 bg-gray-50 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500">
|
||||||
|
{{ $method['label'] }}
|
||||||
|
</button>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($payment_started)
|
||||||
|
<div class="mt-4 container mx-auto flex w-full justify-center">
|
||||||
|
<span class="">
|
||||||
|
<svg class="animate-spin h-8 w-8 text-primary mx-auto justify-center w-full" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none" viewBox="0 0 24 24">
|
||||||
|
<circle class="opacity-75" cx="12" cy="12" r="10" stroke="hsl(210, 70, 75)" stroke-linecap="round"
|
||||||
|
stroke-width="4" animation="dash 1.5s ease-in-out infinite"></circle>
|
||||||
|
<path class="opacity-75" fill="#fff"
|
||||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if(!$email || $errors->has('email'))
|
||||||
<form wire:submit.prevent="handleEmail" class="">
|
<form wire:submit.prevent="handleEmail" class="">
|
||||||
@csrf
|
@csrf
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
@ -259,8 +293,9 @@
|
|||||||
</form>
|
</form>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if($email && !$errors->has('email'))
|
@if($email && !$errors->has('email') && !$authenticated)
|
||||||
<div class="py-6 px-6 w-80 border mx-auto text-center my-6">
|
<div class="py-6 px-6 w-80 mx-auto text-center my-6">
|
||||||
|
<p class="w-full p-2">{{$email}}</p>
|
||||||
<form wire:submit.prevent="handleLogin" class="" x-data="otpForm()">
|
<form wire:submit.prevent="handleLogin" class="" x-data="otpForm()">
|
||||||
<p class="mb-4">{{ ctrans('texts.otp_code_message')}}</p>
|
<p class="mb-4">{{ ctrans('texts.otp_code_message')}}</p>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
@ -276,6 +311,7 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
@error("login")
|
@error("login")
|
||||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
|
||||||
@ -283,6 +319,9 @@
|
|||||||
<span class="absolute top-0 bottom-0 right-0 px-4 py-3">
|
<span class="absolute top-0 bottom-0 right-0 px-4 py-3">
|
||||||
</div>
|
</div>
|
||||||
@enderror
|
@enderror
|
||||||
|
<div class="flex w-full place-content-end mb-0 mt-4">
|
||||||
|
<button wire:click="resetEmail" class="relative -ml-px inline-flex items-center space-x-1 rounded border border-gray-300 bg-gray-50 px-1 py-1 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500">{{ ctrans('texts.reset') }}</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user