diff --git a/assets/controllers/admin_parentgroup_controller.js b/assets/controllers/admin_parentgroup_controller.js index 5cbba13..9d6638d 100644 --- a/assets/controllers/admin_parentgroup_controller.js +++ b/assets/controllers/admin_parentgroup_controller.js @@ -2,7 +2,7 @@ import { Controller} from '@hotwired/stimulus' /* stimulusFetch: 'lazy' */ export default class extends Controller { - static targets = ['servicesEnabledField', 'parentField', 'idField'] + static targets = ['servicesEnabledField', 'parentField', 'idField', 'ownerField'] connect() { const parentFields = document.querySelectorAll('[data-label="Parent"]') @@ -16,6 +16,17 @@ export default class extends Controller { } parentFieldTargetConnected(element) { + // edit page + const parentGroupId = element.value + const servicesEnabledToggle = document.getElementById('Group_servicesEnabled') + this.checkGroupEditDisableServices(parentGroupId, servicesEnabledToggle) + + element.addEventListener('change', () => { + const newParentGroupId = element.value + this.checkGroupEditDisableServices(newParentGroupId, servicesEnabledToggle) + }) + + // list page const observer = new MutationObserver( ( ) => { if (element.tomselect) { observer.disconnect() @@ -65,6 +76,17 @@ export default class extends Controller { }) } + ownerFieldTargetConnected() { + const initialUserId = this.ownerFieldTarget.value + const groupsField = document.getElementById('Product_groups') + this.replaceGroups(initialUserId, groupsField) + this.ownerFieldTarget.addEventListener('change', () => { + const userId = this.ownerFieldTarget.value + + this.replaceGroups(userId, groupsField) + }) + } + async checkDisabledServices(tr) { const id = tr.getAttribute('data-id') const url = `/api/groups/${id}` @@ -122,4 +144,98 @@ export default class extends Controller { }) } + + async replaceGroups(userId, groupsField) { + const url = `/api/groups?user=${userId}&services_enabled=true&admin=0` + const response = await fetch(url, {method: 'GET'}) + if (!response.ok) { + return + } + const data = await response.json() + const groups = data['hydra:member'] + + const parentDiv = groupsField.parentElement + const smallElement = parentDiv.querySelector('small') + + const saveContinue = document.getElementsByClassName('action-saveAndContinue')[0] + const saveReturn = document.getElementsByClassName('action-saveAndReturn')[0] + const saveAdd = document.getElementsByClassName('action-saveAndAddAnother')[0] + + + groupsField.tomselect.clear() + groupsField.tomselect.clearOptions() + if (groups.length === 0) { + groupsField.tomselect.disable() + groupsField.tomselect.lock() + // show helper + if (null !== smallElement) { + smallElement.style.visibility = 'visible' + } + if (undefined !== saveContinue) { + saveContinue.disabled = true + } + if (undefined !== saveAdd) { + saveAdd.disabled = true + } + saveReturn.disabled = true + } else { + groups.map(group => { + groupsField.tomselect.addOption(new Option(group.name, group.id)) + }) + groupsField.tomselect.enable() + groupsField.tomselect.unlock() + + // remove helper + if (null !== smallElement) { + smallElement.style.visibility = 'hidden' + } + if (undefined !== saveContinue) { + saveContinue.disabled = false + } + if (undefined !== saveAdd) { + saveAdd.disabled = false + } + saveReturn.disabled = false + } + } + + async checkGroupEditDisableServices(parentGroupId, servicesEnabledToggle) { + const url = `/api/groups/${parentGroupId}` + + const response = await fetch(url, {method: 'GET'}) + if (!response.ok) { + return + } + const parentGroup = await response.json() + let parentAll = parentGroup.parentsRecursively + parentAll.push(parentGroup['@id']) + + const parentDiv = servicesEnabledToggle.parentElement.parentElement + const smallElement = parentDiv.querySelector('small') + + let disabled = false + for (const parentUrl of parentAll) { + const parentResponse = await fetch(parentUrl, { method: 'GET' }) + if (!response.ok) { + return + } + const parent = await parentResponse.json() + if (!parent.servicesEnabled) { + servicesEnabledToggle.checked = false + servicesEnabledToggle.disabled = true + if (null !== smallElement) { + smallElement.style.visibility = 'visible' + } + disabled = true + break + } + } + + if (!disabled) { + servicesEnabledToggle.disabled = false + if (null !== smallElement) { + smallElement.style.visibility = 'hidden' + } + } + } } diff --git a/src/Controller/Admin/AbstractProductCrudController.php b/src/Controller/Admin/AbstractProductCrudController.php index b5af9e0..9e0ac39 100755 --- a/src/Controller/Admin/AbstractProductCrudController.php +++ b/src/Controller/Admin/AbstractProductCrudController.php @@ -252,7 +252,12 @@ abstract class AbstractProductCrudController extends AbstractCrudController impl $groupsField = AssociationField::new('groups')->onlyOnForms(); $groupsFieldList = CollectionField::new('groups')->hideOnForm(); - $ownerField = AssociationField::new('owner'); + $ownerField = AssociationField::new('owner') + ->setFormTypeOption('attr', [ + 'data-controller' => 'admin-parentgroup', + 'data-admin-parentgroup-target' => 'ownerField', + ]) + ->addWebpackEncoreEntries('admin'); $categoryField = AssociationField::new('category') ->setQueryBuilder(function (QueryBuilder $queryBuilder) { return $this->categoryRepository->addTypeFilter($queryBuilder, $this->getProductType()); diff --git a/src/Controller/Admin/GroupCrudController.php b/src/Controller/Admin/GroupCrudController.php index 09264c8..5759a27 100755 --- a/src/Controller/Admin/GroupCrudController.php +++ b/src/Controller/Admin/GroupCrudController.php @@ -303,7 +303,7 @@ final class GroupCrudController extends AbstractCrudController implements GroupA } } } - array_splice($fields, 3, 0, [$servicesEnabledField]); + array_splice($fields, 4, 0, [$servicesEnabledField]); } return $fields; @@ -328,7 +328,7 @@ final class GroupCrudController extends AbstractCrudController implements GroupA ]; if ($this->configurationRepository->getInstanceConfigurationOrCreate()->getServicesEnabled()) { - array_splice($fields, 2, 0, [$servicesEnabledField]); + array_splice($fields, 3, 0, [$servicesEnabledField]); } return $fields; diff --git a/src/Controller/Admin/ServiceCrudController.php b/src/Controller/Admin/ServiceCrudController.php index 42fe556..70366a8 100644 --- a/src/Controller/Admin/ServiceCrudController.php +++ b/src/Controller/Admin/ServiceCrudController.php @@ -78,6 +78,11 @@ final class ServiceCrudController extends AbstractProductCrudController /** @var ChoiceField $statusField */ $statusField->setChoices(ProductStatus::cases()); + $i18prefix = $this->getI18nPrefix(self::class); + + /** @var AssociationField $groupsField */ + $groupsField->setHelp($i18prefix.'.field.groups.help'); + if ($pageName === Crud::PAGE_NEW) { return [$nameField, $ownerField, $categoryField, $statusField, $groupsField, $descriptionField, $imageField, $durationField]; } @@ -85,7 +90,6 @@ final class ServiceCrudController extends AbstractProductCrudController $product = $this->getContext()?->getEntity()?->getInstance(); $owner = $product?->getOwner(); if (null !== $owner && !$owner->getUserGroupsConfirmedWithServices()->isEmpty()) { - /** @var AssociationField $groupsField */ $groupsField->setQueryBuilder(function (QueryBuilder $queryBuilder) use ($owner) { return $queryBuilder ->join('entity.userGroups', 'ug') @@ -98,9 +102,7 @@ final class ServiceCrudController extends AbstractProductCrudController ; }); } else { - $i18prefix = $this->getI18nPrefix(self::class); - /** @var AssociationField $groupsField */ - $groupsField->setHelp($i18prefix.'.field.groups.help')->setDisabled(); + $groupsField->setDisabled(); } return [$nameField, $ownerField, $categoryField, $statusField, $groupsField, $descriptionField, $imageField, $durationField]; @@ -114,6 +116,7 @@ final class ServiceCrudController extends AbstractProductCrudController $categoryField, $statusField, $visibilityField, + $groupsFieldList, $nameField, $descriptionField, $durationField, diff --git a/src/Repository/GroupRepository.php b/src/Repository/GroupRepository.php index 9031d3f..27c93f8 100644 --- a/src/Repository/GroupRepository.php +++ b/src/Repository/GroupRepository.php @@ -90,7 +90,7 @@ final class GroupRepository extends ServiceEntityRepository /** * @return Group[] */ - public function getGroupsByEnabledServices(bool $servicesEnabled, ?User $user = null): array + public function getGroupsByEnabledServices(bool $servicesEnabled, ?User $user = null, bool $admin = true): array { $qb = $this->createQueryBuilder('g') ->andWhere('g.servicesEnabled = :servicesEnabled') @@ -100,10 +100,15 @@ final class GroupRepository extends ServiceEntityRepository $qb ->leftJoin('g.userGroups', 'gu') ->andWhere('gu.user = :user') - ->andWhere('gu.mainAdminAccount = :mainAdminAccount OR gu.membership = :membership') - ->setParameter('user', $user) - ->setParameter('mainAdminAccount', true) - ->setParameter('membership', UserMembership::ADMIN); + ->setParameter('user', $user); + + if ($admin) { + $qb + ->andWhere('gu.mainAdminAccount = :mainAdminAccount OR gu.membership = :membership') + ->setParameter('mainAdminAccount', true) + ->setParameter('membership', UserMembership::ADMIN) + ; + } } /** @var Group[] */ diff --git a/src/State/GroupsProvider.php b/src/State/GroupsProvider.php index 28e2cc4..d52cded 100644 --- a/src/State/GroupsProvider.php +++ b/src/State/GroupsProvider.php @@ -26,7 +26,9 @@ class GroupsProvider implements ProviderInterface if (isset($context['filters']['user'])) { // @phpstan-ignore-line $user = $this->userRepository->find($context['filters']['user']); - return $this->groupRepository->getGroupsByEnabledServices($context['filters']['services_enabled'] === 'true', $user); // @phpstan-ignore-line + $admin = (bool) ($context['filters']['admin'] ?? true); // @phpstan-ignore-line + + return $this->groupRepository->getGroupsByEnabledServices($context['filters']['services_enabled'] === 'true', $user, $admin); // @phpstan-ignore-line } return $this->groupRepository->getGroupsByEnabledServices($context['filters']['services_enabled'] === 'true'); // @phpstan-ignore-line