diff --git a/resources/views/livewire/profile/experiments-manager.blade.php b/resources/views/livewire/profile/experiments-manager.blade.php index a407ef0..93ed2bb 100644 --- a/resources/views/livewire/profile/experiments-manager.blade.php +++ b/resources/views/livewire/profile/experiments-manager.blade.php @@ -1,6 +1,5 @@ currentView = $this->hasExperiments ? 'list' : 'no-content'; } - /** - * Determine if there are any experiments available. - */ #[Computed] public function hasExperiments(): bool { - $hasExperiments = $this->experiments->isNotEmpty(); - Log::debug('Checking if has experiments', ['hasExperiments' => $hasExperiments]); - return $hasExperiments; + return $this->experiments->isNotEmpty(); } - /** - * Retrieve and process all available experiments. - */ #[Computed] public function experiments(): Collection { - $allFeatures = Feature::all(); - - $experiments = collect($allFeatures) - ->mapWithKeys(function ($value, $key) { - return [$key => $this->getExperimentDetails($key)]; - }); - - Log::debug('Processed experiments', ['count' => $experiments->count(), 'experiments' => $experiments]); - return $experiments; + return collect(Feature::all())->mapWithKeys(fn ($value, $key) => [$key => $this->getExperimentDetails($key)]); } /** - * Toggle the active state of an experiment for the current user. + * Toggles the state of an experiment for the current user. + * + * @param string $experiment The name of the experiment to toggle */ public function toggleExperiment(string $experiment): void { - $user = $this->getCurrentUser(); - $isActive = Feature::for($user)->active($experiment); + $user = Auth::user(); + if (!$user) { + return; + } - Log::debug('Toggling experiment', ['experiment' => $experiment, 'currentState' => $isActive]); + $isActive = Feature::for($user)->active($experiment); + $experimentTitle = $this->getExperimentTitle($experiment); if ($isActive) { - Toaster::success("Experiment '{$this->getExperimentTitle($experiment)}' has been disabled."); Feature::for($user)->deactivate($experiment); - } else { - Toaster::success("Experiment '{$this->getExperimentTitle($experiment)}' has been successfully enabled."); - Feature::for($user)->activate($experiment); + Toaster::success("Experiment '{$experimentTitle}' has been disabled."); + $this->dispatch('experiment-toggled'); + return; } + Feature::for($user)->activate($experiment); + Toaster::success("Experiment '{$experimentTitle}' has been enabled."); $this->dispatch('experiment-toggled'); } - /** - * Switch to the experiments list view. - */ public function viewExperiments(): void { $this->currentView = 'list'; } /** - * Open the details modal for a specific experiment. + * Displays detailed information about a specific experiment. + * + * @param string $experiment The name of the experiment to view */ public function viewExperimentDetails(string $experiment): void { $this->selectedExperiment = $experiment; - Log::debug('Viewing experiment details', ['experiment' => $experiment]); $this->dispatch('open-modal', 'experiment-details'); } - /** - * Open the feedback modal and close the experiment details modal. - */ public function openFeedbackModal(): void { $this->showFeedbackModal = true; @@ -127,46 +99,103 @@ public function openFeedbackModal(): void } /** - * Submit user feedback for the selected experiment. + * Submits user feedback to the external feedback service. + * + * Validates input, sends the feedback, and handles the response. */ public function submitFeedback(): void + { + $this->validateFeedback(); + + try { + $response = $this->sendFeedbackRequest(); + $this->handleFeedbackResponse($response); + } catch (Exception $e) { + $this->handleFeedbackException($e); + } + } + + /** + * Validates the feedback form data. + * + */ + private function validateFeedback(): void { $this->validate([ 'selectedExperiment' => 'required|string|max:255', 'feedbackText' => 'required|string|max:10000', 'feedbackEmail' => 'nullable|email|max:255', ]); + } + /** + * Sends the feedback request to the external service. + * + * @return \Illuminate\Http\Client\Response + */ + private function sendFeedbackRequest(): \Illuminate\Http\Client\Response + { $feedbackServiceUrl = 'https://feedback.vanguardbackup.com/api/feedback'; - try { - $response = Http::post($feedbackServiceUrl, [ - 'experiment' => trim($this->selectedExperiment), - 'feedback' => trim($this->feedbackText), - 'php_version' => trim(phpversion()), - 'vanguard_version' => trim(obtain_vanguard_version()), - 'email_address' => $this->feedbackEmail ? trim($this->feedbackEmail) : null, - ]); - - if ($response->successful() && $response->json('status') === 'success') { - Toaster::success($response->json('message', 'Thank you for your feedback!')); - $this->resetFeedbackForm(); - } elseif ($response->status() === 422) { - $this->handleValidationErrors($response->json('errors')); - } elseif ($response->status() === 429) { - Toaster::error('Too many requests. Please try again later.'); - } else { - throw new RuntimeException('Unexpected response from feedback service'); - } - } catch (Exception $e) { - Log::error('Failed to submit feedback', ['error' => $e->getMessage()]); - Toaster::error('Failed to submit feedback. Please try again later.'); + return Http::post($feedbackServiceUrl, [ + 'experiment' => trim($this->selectedExperiment), + 'feedback' => trim($this->feedbackText), + 'php_version' => trim(phpversion()), + 'vanguard_version' => trim(obtain_vanguard_version()), + 'email_address' => $this->feedbackEmail ? trim($this->feedbackEmail) : null, + ]); + } + + /** + * Handles the response from the feedback service. + * + * @param \Illuminate\Http\Client\Response $response + * @throws RuntimeException + */ + private function handleFeedbackResponse(\Illuminate\Http\Client\Response $response): void + { + if (!$response->successful()) { + $this->handleUnsuccessfulResponse($response); + } + + if ($response->json('status') !== 'success') { + throw new RuntimeException('Unexpected response status from feedback service'); + } + + Toaster::success($response->json('message', 'Your feedback has been successfully submitted. Thank you!')); + $this->resetFeedbackForm(); + } + + /** + * Handles unsuccessful responses from the feedback service. + * + * @param \Illuminate\Http\Client\Response $response + * @throws \RuntimeException + */ + private function handleUnsuccessfulResponse(\Illuminate\Http\Client\Response $response): void + { + if ($response->status() === 422) { + $this->handleValidationErrors($response->json('errors')); + } + + if ($response->status() === 429) { + Toaster::error('Too many requests. Please try again later.'); } + + throw new RuntimeException('Unexpected response from feedback service'); } /** - * Reset the feedback form after successful submission. + * Handles exceptions that occur during the feedback submission process. + * + * @param Exception $e */ + private function handleFeedbackException(\Exception $e): void + { + Log::error('Failed to submit feedback', ['error' => $e->getMessage()]); + Toaster::error('We encountered an issue while submitting your feedback. Please try again later.'); + } + private function resetFeedbackForm(): void { $this->feedbackText = ''; @@ -177,7 +206,9 @@ private function resetFeedbackForm(): void } /** - * Handle validation errors from the API response. + * Handles validation errors from the feedback service. + * + * @param array $errors */ private function handleValidationErrors(array $errors): void { @@ -188,9 +219,6 @@ private function handleValidationErrors(array $errors): void throw ValidationException::withMessages($messages); } - /** - * Close the feedback modal and reopen the experiment details modal. - */ public function closeFeedbackModal(): void { $this->showFeedbackModal = false; @@ -199,28 +227,27 @@ public function closeFeedbackModal(): void } /** - * Retrieve detailed information about a specific experiment. + * Retrieves detailed information about a specific experiment. + * + * @param string $experiment The name of the experiment + * @return array */ private function getExperimentDetails(string $experiment): array { - $user = $this->getCurrentUser(); + $user = Auth::user(); + if (!$user) { + return []; + } + $isActive = Feature::active($experiment) ?? false; $isEnabled = Feature::for($user)->active($experiment) ?? false; $metadata = config("features.{$experiment}", []); - Log::debug('Getting experiment details', [ - 'experiment' => $experiment, - 'isActive' => $isActive, - 'isEnabled' => $isEnabled, - 'metadata' => $metadata, - ]); - return [ 'name' => $experiment, 'title' => $metadata['title'] ?? $this->getExperimentTitle($experiment), 'description' => $metadata['description'] ?? $this->getExperimentDescription($experiment), 'group' => $metadata['group'] ?? 'Uncategorized', - 'rolloutPercentage' => $metadata['rolloutPercentage'] ?? 0, 'icon' => $metadata['icon'] ?? 'heroicon-o-beaker', 'active' => $isActive, 'enabled' => $isEnabled, @@ -228,7 +255,10 @@ private function getExperimentDetails(string $experiment): array } /** - * Generate a human-readable title for an experiment. + * Generates a title for an experiment based on its name. + * + * @param string $experiment The name of the experiment + * @return string */ private function getExperimentTitle(string $experiment): string { @@ -236,23 +266,17 @@ private function getExperimentTitle(string $experiment): string } /** - * Generate a default description for an experiment. + * Generates a description for an experiment based on its name. + * + * @param string $experiment The name of the experiment + * @return string */ private function getExperimentDescription(string $experiment): string { return "This is the {$this->getExperimentTitle($experiment)} experiment."; } - - /** - * Retrieve the current authenticated user. - */ - private function getCurrentUser(): User - { - $user = auth()->user(); - Log::debug('Current user retrieved', ['userId' => $user->id]); - return $user; - } -}; ?> +}; +?>
- {{ __('Experiments are controlled rollouts of new functionalities or improvements to our application. They allow us to test new ideas, gather feedback, and ensure stability before full release. By participating in these experiments, you help shape the future of our product.') }} + {{ __('Feature experiments allow us to introduce new functionalities and improvements in a controlled manner. By participating, you help shape the future of our product and enjoy early access to new features.') }}
- {{ $experiment['enabled'] ? __('Enabled for you') : __('Disabled for you') }} + {{ $experiment['enabled'] ? __('Active for your account') : __('Inactive for your account') }}
{{ __('Note:') }} - {{ __('You may need to reload the page (F5 or Cmd/Ctrl + R) to see the effects of enabling or disabling an experiment.') }} + {{ __('You may need to refresh the page (F5 or Cmd/Ctrl + R) to see changes after activating or deactivating an experiment.') }}