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); return $plan ? $plan->getAllowedProviders() : []; } /** * 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'); } }