feat(payment): implement beautiful payment confirmation page with real-time status checking

- Add PaymentSuccessController with authentication and subscription selection logic
   - Create PaymentConfirmation Livewire component with polling mechanism
   - Implement real-time subscription status verification via Polar provider API
   - Add confetti animation for successful payment confirmation
   - Design responsive payment success page with dark mode support
   - Fix Polar provider field mapping (updated_at -> modified_at)
   - Add comprehensive error handling and logging
   - Support multiple subscription status states (verifying, activated, pending, error)
   - Implement automatic polling with 30-second intervals (max 5 attempts)
   - Add fallback redirects and user-friendly status messages
This commit is contained in:
idevakk
2025-12-04 11:59:09 -08:00
parent 75086ad83b
commit 8950988eac
7 changed files with 781 additions and 2 deletions

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Http\Controllers;
use App\Models\Subscription;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
class PaymentSuccessController extends Controller
{
// Middleware is now registered in bootstrap/app.php for Laravel 12
/**
* Show payment confirmation page after successful checkout
*/
public function show(Request $request): View
{
$user = $request->user();
$sessionToken = $request->get('customer_session_token');
Log::info('PaymentSuccessController: Showing payment confirmation', [
'user_id' => $user->id,
'session_token' => $sessionToken,
]);
// Get the most recent subscription for this user created in the last 15 minutes
// This ensures we're checking the subscription from the current payment session
$recentMinutes = 15;
$subscription = Subscription::where('user_id', $user->id)
->where('created_at', '>=', now()->subMinutes($recentMinutes))
->whereIn('status', ['pending_payment', 'incomplete', 'trialing', 'active']) // Likely statuses for new subscriptions
->orderBy('created_at', 'desc')
->first();
// If no recent subscription found, fall back to the most recent one overall
if (! $subscription) {
Log::info('PaymentSuccessController: No recent subscription found, falling back to most recent', [
'user_id' => $user->id,
'minutes_checked' => $recentMinutes,
]);
$subscription = Subscription::where('user_id', $user->id)
->orderBy('created_at', 'desc')
->first();
}
Log::info('PaymentSuccessController: Subscription selected for status checking', [
'user_id' => $user->id,
'subscription_id' => $subscription?->id,
'provider_subscription_id' => $subscription?->provider_subscription_id,
'provider' => $subscription?->provider,
'status' => $subscription?->status,
'created_at' => $subscription?->created_at,
'is_recent' => $subscription && $subscription->created_at->diffInMinutes(now()) <= $recentMinutes,
]);
return view('payment.success', [
'user' => $user,
'subscription' => $subscription,
'sessionToken' => $sessionToken,
]);
}
}