- Replace getAllowedProviders() method with direct database query - Add filtering for enabled plan providers and active payment providers - Include sort ordering for consistent provider display - Improve performance by using direct database access instead of model method
229 lines
6.4 KiB
PHP
229 lines
6.4 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')
|
|
->pluck('plan_providers.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');
|
|
}
|
|
}
|