From 93f5b716b28fb419c1f3fb4666faa4e4cc31822c Mon Sep 17 00:00:00 2001 From: Brock H Caldwell Date: Wed, 23 Jul 2025 21:17:18 -0500 Subject: [PATCH] fix: creates form for user media preferences --- assets/bootstrap.js | 11 ++- assets/components/brock.js | 25 ++++++ assets/styles/app.css | 2 +- src/User/Database/QualityList.php | 2 +- src/User/Dto/UserPreferencesFactory.php | 4 +- .../Controller/Web/PreferencesController.php | 36 +++++--- .../Form/UserMediaPreferencesForm.php | 60 +++++++++++++ tailwind.config.js | 2 + templates/components/field/select.html.twig | 17 ++++ templates/user/preferences.html.twig | 85 +++---------------- 10 files changed, 150 insertions(+), 94 deletions(-) create mode 100644 assets/components/brock.js create mode 100644 src/User/Framework/Form/UserMediaPreferencesForm.php create mode 100644 templates/components/field/select.html.twig diff --git a/assets/bootstrap.js b/assets/bootstrap.js index 4bd24c8..7d4379e 100644 --- a/assets/bootstrap.js +++ b/assets/bootstrap.js @@ -1,11 +1,14 @@ import { startStimulusApp } from '@symfony/stimulus-bundle'; -import Popover from '@stimulus-components/popover' -import Dialog from '@stimulus-components/dialog' -import Dropdown from '@stimulus-components/dropdown' -import 'animate.css' +import Popover from '@stimulus-components/popover'; +import Dialog from '@stimulus-components/dialog'; +import Dropdown from '@stimulus-components/dropdown'; +import 'animate.css'; +import Brock from './components/brock.js'; const app = startStimulusApp(); // register any custom, 3rd party controllers here app.register('popover', Popover); app.register('dialog', Dialog); app.register('dropdown', Dropdown); + +customElements.define('brock-app', Brock); diff --git a/assets/components/brock.js b/assets/components/brock.js new file mode 100644 index 0000000..8b3462f --- /dev/null +++ b/assets/components/brock.js @@ -0,0 +1,25 @@ +export default class Brock extends HTMLElement { + constructor() { + super(); + } + connectedCallback() { + this.render(); + } + + render() { + this.innerHTML = ` + Yo, yo, yo! Waddup ${this.name}, doe, it's Brocky fresh! + `; + } + + // attribute change + attributeChangedCallback(property, oldValue, newValue) { + if (oldValue === newValue) return; + this[ property ] = newValue; + this.render(); + } + + static get observedAttributes() { + return ['name']; + } +} diff --git a/assets/styles/app.css b/assets/styles/app.css index cdeaa64..c94a5a1 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -65,7 +65,7 @@ dialog[data-dialog-target="dialog"][closing] { } .text-input { - @apply bg-gray-50 text-gray-50 p-1 bg-transparent border-b-2 border-orange-400 + @apply bg-gray-50 text-gray-50 px-2 py-1 bg-transparent border-b-2 border-orange-400 } .submit-button { diff --git a/src/User/Database/QualityList.php b/src/User/Database/QualityList.php index 1ef9251..0926542 100644 --- a/src/User/Database/QualityList.php +++ b/src/User/Database/QualityList.php @@ -102,7 +102,7 @@ class QualityList public static function asSelectOptions(): array { - $result = []; + $result = ['n/a' => null]; foreach (array_keys(static::$qualities) as $quality) { $result[$quality] = $quality; } diff --git a/src/User/Dto/UserPreferencesFactory.php b/src/User/Dto/UserPreferencesFactory.php index ef15ea0..9375ac7 100644 --- a/src/User/Dto/UserPreferencesFactory.php +++ b/src/User/Dto/UserPreferencesFactory.php @@ -34,14 +34,14 @@ class UserPreferencesFactory private static function getNestedValue(UserInterface $user, string $preferenceId): ?string { $preference = $user->getUserPreference($preferenceId); - if (null === $preference) { + if (null === $preference || "" === $preference || null === $preference->getPreferenceValue() || "" === $preference->getPreferenceValue()) { return null; } return $preference->getPreference() ->getPreferenceOptions() ->filter(fn (PreferenceOption $option) => (string) $option->getId() === $preference->getPreferenceValue()) ->first() - ->getValue() + ->getId() ; } } diff --git a/src/User/Framework/Controller/Web/PreferencesController.php b/src/User/Framework/Controller/Web/PreferencesController.php index 3dcee51..b5450a8 100644 --- a/src/User/Framework/Controller/Web/PreferencesController.php +++ b/src/User/Framework/Controller/Web/PreferencesController.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\User\Framework\Controller\Web; use App\Base\Service\Broadcaster; +use App\User\Action\Command\SaveUserMediaPreferencesCommand; use App\User\Action\Handler\SaveUserDownloadPreferencesHandler; use App\User\Action\Handler\SaveUserMediaPreferencesHandler; use App\User\Action\Input\SaveUserDownloadPreferencesInput; @@ -14,8 +15,10 @@ use App\User\Database\ProviderList; use App\User\Database\QualityList; use App\User\Dto\UserPreferencesFactory; use App\User\Framework\Form\GettingStartedFilterForm; +use App\User\Framework\Form\UserMediaPreferencesForm; use App\User\Framework\Repository\PreferencesRepository; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; @@ -26,24 +29,35 @@ class PreferencesController extends AbstractController private readonly Broadcaster $broadcaster, ) {} - #[Route('/user/preferences', 'app_user_preferences', methods: ['GET'])] - public function mediaPreferences(): Response + #[Route('/user/preferences', 'app_user_preferences', methods: ['GET', 'POST'])] + public function mediaPreferences(Request $request, SaveUserMediaPreferencesHandler $saveUserMediaPreferencesHandler): Response { - $mediaPreferences = $this->getUser()->getMediaPreferences(); $downloadPreferences = $this->getUser()->getDownloadPreferences(); - $languages = CountryLanguages::$languages; - sort($languages); + $formData = (array) UserPreferencesFactory::createFromUser($this->getUser()); + $form = $this->createForm(UserMediaPreferencesForm::class, $formData); + + if ($request->isMethod('POST')) { + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $saveUserMediaPreferencesHandler->handle(new SaveUserMediaPreferencesCommand( + resolution: (string) $form->get('resolution')->getData(), + codec: (string) $form->get('codec')->getData(), + quality: (string) $form->get('quality')->getData(), + language: (string) $form->get('language')->getData(), + provider: (string) $form->get('provider')->getData(), + )); + $this->broadcaster->alert( + title: 'Success', + message: 'Your media preferences have been saved.' + ); + } + } return $this->render( 'user/preferences.html.twig', [ - 'preferences' => $this->preferencesRepository->findEnabled(), - 'languages' => $languages, - 'providers' => ProviderList::getProviders(), - 'qualities' => QualityList::getBaseQualities(), - 'mediaPreferences' => $mediaPreferences, 'downloadPreferences' => $downloadPreferences, - 'filterForm' => $this->createForm(GettingStartedFilterForm::class, (array) UserPreferencesFactory::createFromUser($this->getUser())), + 'preferences_form' => $form, ] ); } diff --git a/src/User/Framework/Form/UserMediaPreferencesForm.php b/src/User/Framework/Form/UserMediaPreferencesForm.php new file mode 100644 index 0000000..a7cf1be --- /dev/null +++ b/src/User/Framework/Form/UserMediaPreferencesForm.php @@ -0,0 +1,60 @@ +addChoiceField($builder, 'language', CountryLanguages::asSelectOptions()); + $this->addChoiceField($builder, 'quality', QualityList::asSelectOptions()); + $this->addChoiceField($builder, 'provider', ProviderList::asSelectOptions()); + $this->addChoiceField($builder, 'resolution', $this->getPreferenceChoices('resolution')); + $this->addChoiceField($builder, 'codec', $this->getPreferenceChoices('codec')); + } + + private function addChoiceField(FormBuilderInterface $builder, string $fieldName, array $choices): void + { + $question = [ + 'attr' => ['class' => 'w-64 text-input mb-4'], + 'label_attr' => ['class' => 'w-64 text-white block font-semibold mb-2'], + 'choices' => $this->addDefaultChoice($choices), + 'required' => false, + ]; + $builder->add($fieldName, ChoiceType::class, $question); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([]); + } + + private function getPreferenceChoices(string $preference): array + { + $options = $this->preferenceOptionRepository->findBy(['preference' => $preference]); + $result = []; + foreach ($options as $item) { + $result[$item->getName()] = $item->getId(); + } + return $result; + } + + private function addDefaultChoice(array $choices): iterable + { + return ['n/a' => ''] + $choices; + } +} diff --git a/tailwind.config.js b/tailwind.config.js index 599a018..cdfef2a 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -10,6 +10,8 @@ module.exports = { "flex-row", "p-2", "p-4", + "w-32", + "w-64", "bg-blue-300", "bg-orange-300", "bg-fuchsia-300", diff --git a/templates/components/field/select.html.twig b/templates/components/field/select.html.twig new file mode 100644 index 0000000..b2c6e57 --- /dev/null +++ b/templates/components/field/select.html.twig @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/templates/user/preferences.html.twig b/templates/user/preferences.html.twig index 4b8d740..f649905 100644 --- a/templates/user/preferences.html.twig +++ b/templates/user/preferences.html.twig @@ -5,84 +5,19 @@ {% block body %}
-

Define a filter to be pre-applied to your download options.

-
- - - - - - - - - - - - - - - -
+

Define a filter to be pre-applied to your download options.

+ {{ form_start(preferences_form) }} + {{ form_row(preferences_form.language) }} + {{ form_row(preferences_form.quality) }} + {{ form_row(preferences_form.provider) }} + {{ form_row(preferences_form.resolution) }} + {{ form_row(preferences_form.codec) }} + + {{ form_end(preferences_form) }}
-

Change how your downloads are stored.

+

Change how your downloads are stored.