feat(payment): implement secure payment cancellation page with session tracking

- Create PaymentCancelController with authentication and subscription detection
  - Design responsive cancellation view with red/orange gradient theme
  - Add session token logging and recent subscription lookup functionality
  - Update payment cancel route to use new controller with auth middleware
  - Include security assurances and proper navigation to checkout/dashboard
  - Remove broken route references and ensure all buttons link to valid pages
This commit is contained in:
idevakk
2025-12-05 06:59:08 -08:00
parent 34183dc3cb
commit ebb041c0cc
3 changed files with 209 additions and 1 deletions

View File

@@ -0,0 +1,154 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Payment Cancelled - {{ config('app.name') }}</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
// Initialize dark mode detection
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
</script>
</head>
<body class="min-h-screen bg-gradient-to-br from-red-50 via-white to-orange-50 dark:from-gray-900 dark:via-gray-800 dark:to-gray-900">
<!-- Navigation Header -->
<header class="bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm border-b border-gray-200 dark:border-gray-700 sticky top-0 z-50">
<div class="container mx-auto px-4">
<div class="flex items-center justify-between h-16">
<div class="flex items-center gap-3">
<div class="flex items-center gap-2">
<div class="w-8 h-8 bg-gradient-to-r from-red-600 to-orange-600 rounded-lg flex items-center justify-center">
<span class="text-white font-bold text-sm">Z</span>
</div>
<h1 class="text-xl font-bold bg-gradient-to-r from-red-600 to-orange-600 bg-clip-text text-transparent">
Zemailnator
</h1>
</div>
</div>
<a href="{{ route('dashboard') }}"
class="inline-flex items-center gap-2 px-4 py-2 text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
</svg>
Back to Dashboard
</a>
</div>
</div>
</header>
<!-- Main Content -->
<main class="flex items-center justify-center min-h-[calc(100vh-4rem)] p-4">
<div class="w-full max-w-2xl">
<!-- Payment Status Card -->
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-2xl overflow-hidden">
<!-- Cancellation Header -->
<div class="bg-gradient-to-r from-red-600 to-orange-600 p-8 text-center">
<div class="inline-flex items-center justify-center w-16 h-16 bg-white/20 rounded-full mb-4">
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</div>
<h2 class="text-2xl font-bold text-white mb-2">
Payment Cancelled
</h2>
<p class="text-red-100 text-lg">
Your payment session has been cancelled. No charges were made.
</p>
</div>
<!-- Cancellation Details -->
<div class="p-8">
<div class="text-center mb-8">
<div class="inline-flex items-center justify-center w-20 h-20 bg-red-100 dark:bg-red-900/20 rounded-full mb-4">
<svg class="w-10 h-10 text-red-600 dark:text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 15.5c-.77.833.192 2.5 1.732 2.5z"></path>
</svg>
</div>
<h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-3">
No worries, your subscription wasn't created
</h3>
<p class="text-gray-600 dark:text-gray-400 mb-6">
You can try subscribing again anytime. Your payment information is secure and no charges were processed.
</p>
<!-- Recent Subscription Info (if available) -->
@if ($recentSubscription)
<div class="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-4 mb-6">
<div class="flex items-center">
<svg class="w-5 h-5 text-yellow-600 dark:text-yellow-400 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<p class="text-sm text-yellow-800 dark:text-yellow-200">
We found a recent subscription attempt that was cancelled. You can try again from the pricing page.
</p>
</div>
</div>
@endif
</div>
<!-- Action Buttons -->
<div class="flex flex-col sm:flex-row gap-4 justify-center">
<a href="{{ route('dashboard') }}"
class="inline-flex items-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white font-medium rounded-lg hover:from-blue-700 hover:to-purple-700 transition-all duration-200 shadow-lg hover:shadow-xl">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"></path>
</svg>
Try Again
</a>
<a href="{{ route('dashboard') }}"
class="inline-flex items-center gap-2 px-6 py-3 bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-300 font-medium rounded-lg border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-600 transition-all duration-200">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path>
</svg>
Go to Dashboard
</a>
</div>
</div>
</div>
<!-- Info Section -->
<div class="mt-6 text-center">
<div class="inline-flex items-center gap-2 px-4 py-2 bg-gray-100 dark:bg-gray-700 rounded-lg">
<svg class="w-4 h-4 text-gray-600 dark:text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<span class="text-sm text-gray-600 dark:text-gray-400">
Session: {{ $sessionToken ? substr($sessionToken, 0, 20) . '...' : 'Not provided' }}
</span>
</div>
</div>
<!-- Security Assurance -->
<div class="mt-6 text-center">
<div class="inline-flex items-center gap-2 px-4 py-2 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg">
<svg class="w-4 h-4 text-green-600 dark:text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>
</svg>
<span class="text-sm text-green-800 dark:text-green-200 font-medium">
Your payment information is secure. No charges were made.
</span>
</div>
</div>
</div>
</main>
<!-- Custom Styles -->
<style>
@keyframes pulse-scale {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.animate-pulse-scale {
animation: pulse-scale 2s ease-in-out infinite;
}
</style>
</body>
</html>