when I try to create a new subscription I get this error (This customer has no attached payment source or default payment method. ) so I checked the PaymentController with dd($paymentMethod) which returned null
so I don't know why the variable $paymentMethod in store method is returning NULL from the $request but the request, for the price is returning the price_id. Please any help is appreciated
but when console.log() setupIntent.payment_method it returned the payment_method in the console
Here is my PaymentController
public function index()
{
$availablePlans = [
'price_1HnIiLLzAo4pwMcyh2aGaznB' => 'Monthly',
'price_1HnJ2vLzAo4pwMcygQT66juk' => 'Yearly',
'price_1HnIhILzAo4pwMcy9iH3j30L' => 'Free Membership'
];
$user = auth()->user();
$data = [
'intent' => $user->createSetupIntent(),
'plans' => $availablePlans
];
return view('payments.checkout')->with($data);
}
public function store(Request $request)
{
$user = auth()->user();
$paymentMethod = $request->payment_method;
// dd($paymentMethod);
$planId = $request->plan;
$user->newSubscription('premium', $planId)->create($paymentMethod);
return response(['status' => 'success']);
}
This is the Javascript
window.addEventListener('load', function (){
// Create a Stripe client. const stripe = Stripe('pk_test_51H2OqqLzAo4pwMcyT4h405wpFRAn3FWhvByfvmVnW6tabrIsDoU1dBXJ0UaWexUJeacCJ9uKpb5OBmmA2KaCg4sd00ZZ5tj2q8');
// Create an instance of Elements.
const elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide below.)
// const cardElement = elements.create('card', {style: style});
// Create an instance of the card Element.
const cardElement = elements.create('card');
// Add an instance of the card Element into the `card-element` <div>.
cardElement.mount('#card-element');
const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');
const clientSecret = cardButton.dataset.secret;
const plan = document.getElementById('subscription-plan').value;
cardButton.addEventListener('click', async (e) => {
const { setupIntent, error } = await stripe.handleCardSetup(
clientSecret, cardElement, {
payment_method_data: {
billing_details: { name: cardHolderName.value }
}
}
);
if (error) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
// console.log('handling success', setupIntent.payment_method);
axios.post('/subscribe', {
payment_method: setupIntent.payment_method,
plan: plan
})
}
});
});
Here is the form
<form action="{{ route('subscribe')}}" method="POST" id="">
@csrf
<div class="form-content">
<div class="field">
<select class="form-control" name="plan" id="subscription-plan">
@foreach ($plans as $key=>$plan )
<option value="{{$key}}">{{$plan}}</option>
@endforeach
</select>
</div>
<div class="field">
<input type="text" autocorrect="off" spellcheck="false" id="card-holder-name" maxlength="25" />
<span class="focus-bar"></span>
<label for="cardholder">Card holder (Name on card)</label>
</div>
<div class="field mb-5" id="card-element">
<!-- Stripe Elements Placeholder -->
</div>
<button id="card-button" data-secret="{{ $intent->client_secret }}"><span>Pay</span></button>
</div>
</form>
The Route
Route::resource('payments', 'PaymentsController', [
'names'=> [
'index' => 'checkout',
'store' => 'subscribe',
]
]);