Files
zemailnator/app/Livewire/Dashboard/Pricing.php
idevakk 3b908484de refactor(pricing): dynamic payment provider buttons with database-driven text
- Replace hardcoded provider-specific buttons with dynamic database-driven approach
  - Update getPlanProviders() to include display_name from payment_providers table
  - Simplify plan-card.blade.php with single if/else logic for all providers
  - Move trial button outside loop and comment for future implementation
  - Use "Pay with {display_name}" pattern for consistent button text
  - Maintain special handling for activation_key provider with disabled state
2025-12-02 11:58:44 -08:00

231 lines
6.5 KiB
PHP

<?php
namespace App\Livewire\Dashboard;
use App\Models\ActivationKey;
use App\Models\Plan;
use App\Models\PlanTier;
use Exception;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Log;
use Livewire\Component;
class Pricing extends Component
{
public $plans;
public $planTiers;
public $activation_key;
public $selectedProvider = 'stripe';
public $selectedBillingCycle = null;
public $selectedTier = null;
public function mount(): void
{
$this->loadPlans();
$this->planTiers = PlanTier::with('plans')->orderBy('sort_order')->get();
}
private function loadPlans(): void
{
$query = Plan::active()
->ordered()
->with(['planFeatureLimits.planFeature', 'planProviders', 'trialConfiguration', 'planTier']);
if ($this->selectedTier) {
$query->where('plan_tier_id', $this->selectedTier);
}
$this->plans = $query->get();
}
public function filterByTier($tierId = null): void
{
$this->selectedTier = $tierId;
$this->loadPlans();
}
public function choosePlan($planId, $provider = 'stripe'): void
{
$plan = Plan::findOrFail($planId);
if (! $plan?->supportsProvider($provider)) {
session()->flash('error', "This plan doesn't support {$provider} payments.");
return;
}
$this->redirect(route('checkout.enhanced', [
'plan' => $planId,
'provider' => $provider,
]));
}
public function startTrial($planId, $provider = 'stripe'): void
{
$plan = Plan::findOrFail($planId);
if (! $plan?->hasTrial()) {
session()->flash('error', "This plan doesn't offer trials.");
return;
}
if (! $plan?->supportsProvider($provider)) {
session()->flash('error', "This plan doesn't support {$provider} payments for trials.");
return;
}
$this->redirect(route('checkout.trial', [
'plan' => $planId,
'provider' => $provider,
]));
}
public function activateKey(): void
{
$this->validate([
'activation_key' => 'required|alpha_num|max:30',
], [
'activation_key.required' => 'You must enter an activation key.',
'activation_key.alpha_num' => 'The activation key may only contain letters and numbers (no special characters).',
'activation_key.max' => 'The activation key must not exceed 30 characters.',
]);
$trimmedKey = trim((string) $this->activation_key);
$activation = ActivationKey::query()->where('activation_key', $trimmedKey)
->where('is_activated', false)
->first();
if ($activation) {
try {
$result = $this->activateSubscriptionKey($activation);
if ($result) {
session()->flash('success', 'Activation key is valid and has been activated. Refresh page to see changes.');
$this->reset('activation_key');
} else {
session()->flash('error', 'Something went wrong. Kindly drop a mail at contact@zemail.me to activate your subscription manually.');
}
} catch (Exception $e) {
Log::error('Activation key error: '.$e->getMessage());
session()->flash('error', 'An error occurred while activating your key. Please contact support.');
}
} else {
session()->flash('error', 'Invalid or already activated key.');
}
}
private function activateSubscriptionKey(ActivationKey $activation): bool
{
try {
// Use the ActivationKeyProvider directly
$provider = app(\App\Services\Payments\Providers\ActivationKeyProvider::class);
$user = auth()->user();
// Redeem the activation key using the provider
$result = $provider->redeemActivationKey($activation->activation_key, $user);
if ($result['success']) {
// Mark activation key as used
$activation->is_activated = true;
$activation->user_id = $user->id;
$activation->save();
return true;
}
Log::error('Activation key redemption failed: '.$result['message'] ?? 'Unknown error');
return false;
} catch (Exception $e) {
Log::error('Activation key processing failed: '.$e->getMessage());
return false;
}
}
/**
* Get available providers for a plan
*/
public function getPlanProviders($planId): array
{
$plan = $this->plans->firstWhere('id', $planId);
if (! $plan) {
return [];
}
return $plan->planProviders()
->enabled()
->join('payment_providers', 'plan_providers.provider', '=', 'payment_providers.name')
->where('payment_providers.is_active', true)
->orderBy('plan_providers.sort_order')
->select('plan_providers.provider', 'payment_providers.display_name')
->get()
->keyBy('provider')
->toArray();
}
/**
* Get plan features with limits
*/
public function getPlanFeatures($planId): array
{
$plan = $this->plans->firstWhere('id', $planId);
if (! $plan) {
return [];
}
return $plan->getFeaturesWithLimits();
}
/**
* Check if plan has trial available
*/
public function planHasTrial($planId): bool
{
$plan = $this->plans->firstWhere('id', $planId);
return $plan ? $plan->hasTrial() : false;
}
/**
* Get trial configuration for plan
*/
public function getTrialConfig($planId): ?array
{
$plan = $this->plans->firstWhere('id', $planId);
if (! $plan || ! $plan->hasTrial()) {
return null;
}
$config = $plan->getTrialConfig();
return [
'duration_days' => $config->trial_duration_days,
'requires_payment_method' => $config->trial_requires_payment_method,
'auto_converts' => $config->trial_auto_converts,
];
}
/**
* Get billing cycle display text
*/
public function getBillingCycleDisplay($plan): string
{
return $plan->getBillingCycleDisplay();
}
public function render(): Factory|View
{
return view('livewire.dashboard.pricing');
}
}