From 245c3fa121792f1a9be45850ba447d70cf578d35 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 11 Feb 2025 14:22:57 +0100 Subject: [PATCH 01/50] First commit - changie for feature --- .changes/unreleased/Feature-20250211-142243.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changes/unreleased/Feature-20250211-142243.yaml diff --git a/.changes/unreleased/Feature-20250211-142243.yaml b/.changes/unreleased/Feature-20250211-142243.yaml new file mode 100644 index 000000000..4f0b25e88 --- /dev/null +++ b/.changes/unreleased/Feature-20250211-142243.yaml @@ -0,0 +1,6 @@ +kind: Feature +body: Allow the merge of two accompanying period works +time: 2025-02-11T14:22:43.134106669+01:00 +custom: + Issue: "359" + SchemaChange: No schema change From 668720984d9634d1b3939444c9734704db2ca166 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 11 Feb 2025 15:06:04 +0100 Subject: [PATCH 02/50] WIP merge service --- .../AccompanyingPeriodWorkMergeService.php | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeService.php diff --git a/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeService.php b/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeService.php new file mode 100644 index 000000000..155a180a7 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeService.php @@ -0,0 +1,127 @@ +transferData($toKeep, $toDelete); + + // Update linked entities + $this->updateReferences($toKeep, $toDelete); + + $this->em->remove($toDelete); + $this->em->flush(); + } + + private function transferData(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void + { + $excludedProperties = ['id', 'createdAt', 'createdBy', 'updatedAt', 'updatedBy']; + $reflection = new \ReflectionClass(AccompanyingPeriodWork::class); + + foreach ($reflection->getProperties() as $property) { + if (in_array($property->getName(), $excludedProperties, true)) { + continue; + } + + $toKeepValue = $property->getValue($toKeep); + $toDeleteValue = $property->getValue($toDelete); + + if (null === $toKeepValue && null !== $toDeleteValue) { + $property->setValue($toKeep, $toDeleteValue); + } + + if ($toKeepValue instanceof Collection + && $toDeleteValue instanceof Collection) { + foreach ($toDeleteValue as $item) { + if (!$toKeepValue->contains($item)) { + $toKeepValue->add($item); + } + } + } + } + } + + private function updateReferences(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void + { + $allMeta = $this->em->getMetadataFactory()->getAllMetadata(); + + foreach ($allMeta as $meta) { + foreach ($meta->getAssociationMappings() as $assoc) { + if (AccompanyingPeriodWork::class !== $assoc['targetEntity']) { + continue; // Skip unrelated associations + } + + $entityClass = $meta->getName(); + $associationField = $assoc['fieldName']; + + if ($assoc['type'] & ClassMetadata::TO_ONE) { + // Handle ManyToOne or OneToOne + $qb = $this->em->createQueryBuilder(); + $qb->update($entityClass, 'e') + ->set("e.{$associationField}", ':toKeep') + ->where("e.{$associationField} = :toDelete") + ->setParameter('toKeep', $toKeep) + ->setParameter('toDelete', $toDelete) + ->getQuery() + ->execute(); + } + + if ($assoc['type'] & ClassMetadata::TO_MANY) { + // Handle ManyToMany or OneToMany (inverse side) + $repo = $this->em->getRepository($entityClass); + $linkedEntities = $repo->createQueryBuilder('e') + ->join("e.{$associationField}", 't') + ->where('t = :toDelete') + ->setParameter('toDelete', $toDelete) + ->getQuery() + ->getResult(); + + foreach ($linkedEntities as $entity) { + $getter = 'get'.ucfirst($associationField); + $setter = 'set'.ucfirst($associationField); + $adder = 'add'.ucfirst(rtrim($associationField, 's')); + $remover = 'remove'.ucfirst(rtrim($associationField, 's')); + + if (method_exists($entity, $getter) && method_exists($entity, $setter)) { + // For OneToMany owning side + $collection = $entity->{$getter}(); + if ($collection->contains($toDelete)) { + $collection->removeElement($toDelete); + if (!$collection->contains($toKeep)) { + $collection->add($toKeep); + } + } + } elseif (method_exists($entity, $adder) && method_exists($entity, $remover)) { + // For ManyToMany + $entity->{$remover}($toDelete); + $entity->{$adder}($toKeep); + } + + $this->em->persist($entity); + } + } + } + } + + $this->em->flush(); + } +} From 95d80ce13eed5d2c58de65acbd1264a1df12c9fa Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 11 Feb 2025 16:46:44 +0100 Subject: [PATCH 03/50] Improve merge service according to specifications --- .../AccompanyingPeriodWorkMergeService.php | 181 +++++++++++------- 1 file changed, 114 insertions(+), 67 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeService.php b/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeService.php index 155a180a7..4b48ffcbf 100644 --- a/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeService.php +++ b/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeService.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Chill\PersonBundle\Service\AccompanyingPeriodWork; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; -use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Exception; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; @@ -20,6 +20,9 @@ class AccompanyingPeriodWorkMergeService { public function __construct(private readonly EntityManagerInterface $em) {} + /** + * @throws Exception + */ public function merge(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void { // Transfer non-duplicate data @@ -32,96 +35,140 @@ class AccompanyingPeriodWorkMergeService $this->em->flush(); } + /** + * @throws Exception + */ private function transferData(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void { - $excludedProperties = ['id', 'createdAt', 'createdBy', 'updatedAt', 'updatedBy']; - $reflection = new \ReflectionClass(AccompanyingPeriodWork::class); + $conn = $this->em->getConnection(); - foreach ($reflection->getProperties() as $property) { - if (in_array($property->getName(), $excludedProperties, true)) { - continue; - } - - $toKeepValue = $property->getValue($toKeep); - $toDeleteValue = $property->getValue($toDelete); - - if (null === $toKeepValue && null !== $toDeleteValue) { - $property->setValue($toKeep, $toDeleteValue); - } - - if ($toKeepValue instanceof Collection - && $toDeleteValue instanceof Collection) { - foreach ($toDeleteValue as $item) { - if (!$toKeepValue->contains($item)) { - $toKeepValue->add($item); - } - } + $sqlStatements = [ + $this->generateStartDateSQL(), + $this->generateEndDateSQL(), + $this->generateCommentSQL(), + ]; + + $conn->beginTransaction(); + + try { + foreach ($sqlStatements as $sql) { + $conn->executeQuery($sql, ['toDelete' => $toDelete->getId(), 'toKeep' => $toKeep->getId()]); } + $conn->commit(); + } catch (\Exception $e) { + $conn->rollBack(); + throw $e; } } + private function generateStartDateSQL(): string + { + return ' + UPDATE chill_person_accompanying_period_work + SET startdate = LEAST( + COALESCE((SELECT startdate FROM chill_person_accompanying_period_work WHERE id = :toDelete), startdate), + startdate + ) + WHERE id = :toKeep'; + } + + private function generateEndDateSQL(): string + { + return ' + UPDATE chill_person_accompanying_period_work + SET enddate = + CASE + WHEN (SELECT enddate FROM chill_person_accompanying_period_work WHERE id = :toDelete) IS NULL + OR enddate IS NULL + THEN NULL + ELSE GREATEST( + COALESCE((SELECT enddate FROM chill_person_accompanying_period_work WHERE id = :toDelete), enddate), + enddate + ) + END + WHERE id = :toKeep'; + } + + private function generateCommentSQL(): string + { + return " + UPDATE chill_person_accompanying_period_work + SET note = CONCAT_WS( + '\n', + NULLIF(TRIM(note), ''), + NULLIF(TRIM((SELECT note FROM chill_person_accompanying_period_work WHERE id = :toDelete)), '') + ) + WHERE id = :toKeep"; + } + + /** + * @throws Exception + */ private function updateReferences(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void { $allMeta = $this->em->getMetadataFactory()->getAllMetadata(); + $conn = $this->em->getConnection(); + $sqlStatements = []; foreach ($allMeta as $meta) { + if ($meta->isMappedSuperclass) { + continue; + } + foreach ($meta->getAssociationMappings() as $assoc) { if (AccompanyingPeriodWork::class !== $assoc['targetEntity']) { - continue; // Skip unrelated associations + continue; } - $entityClass = $meta->getName(); - $associationField = $assoc['fieldName']; - if ($assoc['type'] & ClassMetadata::TO_ONE) { - // Handle ManyToOne or OneToOne - $qb = $this->em->createQueryBuilder(); - $qb->update($entityClass, 'e') - ->set("e.{$associationField}", ':toKeep') - ->where("e.{$associationField} = :toDelete") - ->setParameter('toKeep', $toKeep) - ->setParameter('toDelete', $toDelete) - ->getQuery() - ->execute(); + if ('handlingThirdparty' === $assoc['fieldName']) { + continue; + } + $sqlStatements[] = $this->generateToOneUpdateQuery($meta, $assoc); } if ($assoc['type'] & ClassMetadata::TO_MANY) { - // Handle ManyToMany or OneToMany (inverse side) - $repo = $this->em->getRepository($entityClass); - $linkedEntities = $repo->createQueryBuilder('e') - ->join("e.{$associationField}", 't') - ->where('t = :toDelete') - ->setParameter('toDelete', $toDelete) - ->getQuery() - ->getResult(); - - foreach ($linkedEntities as $entity) { - $getter = 'get'.ucfirst($associationField); - $setter = 'set'.ucfirst($associationField); - $adder = 'add'.ucfirst(rtrim($associationField, 's')); - $remover = 'remove'.ucfirst(rtrim($associationField, 's')); - - if (method_exists($entity, $getter) && method_exists($entity, $setter)) { - // For OneToMany owning side - $collection = $entity->{$getter}(); - if ($collection->contains($toDelete)) { - $collection->removeElement($toDelete); - if (!$collection->contains($toKeep)) { - $collection->add($toKeep); - } - } - } elseif (method_exists($entity, $adder) && method_exists($entity, $remover)) { - // For ManyToMany - $entity->{$remover}($toDelete); - $entity->{$adder}($toKeep); - } - - $this->em->persist($entity); + if (!isset($assoc['joinTable'])) { + continue; } + $sqlStatements = array_merge($sqlStatements, $this->generateToManyUpdateQueries($assoc)); } } } - $this->em->flush(); + $conn->beginTransaction(); + try { + foreach ($sqlStatements as $sql) { + $conn->executeStatement($sql, ['toDelete' => $toDelete->getId(), 'toKeep' => $toKeep->getId()]); + } + $conn->commit(); + } catch (\Exception $e) { + $conn->rollBack(); + throw $e; + } + } + + private function generateToOneUpdateQuery(ClassMetadata $meta, array $assoc): string + { + $tableName = $meta->getTableName(); + $joinColumn = $meta->getSingleAssociationJoinColumnName($assoc['fieldName']); + + return "UPDATE {$tableName} SET {$joinColumn} = :toKeep WHERE {$joinColumn} = :toDelete"; + } + + private function generateToManyUpdateQueries(array $assoc): array + { + $sqls = []; + $joinTable = $assoc['joinTable']['name']; + $owningColumn = $assoc['joinTable']['joinColumns'][0]['name']; + $inverseColumn = $assoc['joinTable']['inverseJoinColumns'][0]['name']; + + // Insert relations, skip already existing ones + $sqls[] = "INSERT IGNORE INTO {$joinTable} ({$owningColumn}, {$inverseColumn}) + SELECT :toKeep, {$inverseColumn} FROM {$joinTable} WHERE {$owningColumn} = :toDelete"; + // Delete old references + $sqls[] = "DELETE FROM {$joinTable} WHERE {$owningColumn} = :toDelete"; + + return $sqls; } } From d97d5e689a14b8c410758af03a1e9cd691a0135f Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 11 Feb 2025 17:51:29 +0100 Subject: [PATCH 04/50] Create types --- .../Resources/public/types.ts | 49 +++++++++++++++++++ .../Resources/public/types.ts | 1 + 2 files changed, 50 insertions(+) create mode 100644 src/Bundle/ChillThirdPartyBundle/Resources/public/types.ts diff --git a/src/Bundle/ChillPersonBundle/Resources/public/types.ts b/src/Bundle/ChillPersonBundle/Resources/public/types.ts index 5e75553a5..c93440d75 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/types.ts +++ b/src/Bundle/ChillPersonBundle/Resources/public/types.ts @@ -7,6 +7,7 @@ import { WorkflowAvailable, } from "../../../ChillMainBundle/Resources/public/types"; import { StoredObject } from "../../../ChillDocStoreBundle/Resources/public/types"; +import {Thirdparty} from "../../../ChillThirdPartyBundle/Resources/public/types"; export interface Person { id: number; @@ -41,3 +42,51 @@ export interface AccompanyingPeriodWorkEvaluationDocument { workflows_availables: WorkflowAvailable[]; workflows: object[]; } + +export interface AccompanyingPeriodWork { + id?: number; + accompanyingPeriod?: AccompanyingPeriod; + accompanyingPeriodWorkEvaluations: AccompanyingPeriodWorkEvaluation[]; + createdAt?: string; + createdAutomatically: boolean; + createdAutomaticallyReason: string; + createdBy: User; + endDate?: string; + goals: AccompanyingPeriodWorkGoal[]; + handlingThierParty?: Thirdparty; + note: string; + persons: Person[]; + privateComment: PrivateCommentEmbeddable; + referrersHistory: AccompanyingPeriodWorkReferrerHistory[]; + results: Result[]; + socialAction?: SocialAction; + startDate?: string; + thirdParties: Thirdparty[]; + updatedAt?: string; + updatedBy: User; + version: number; +} + +interface SocialAction { + id?: number; + parent?: SocialAction | null; + children: SocialAction[]; + issue?: SocialIssue | null; + ordering: number; + title: Record; + defaultNotificationDelay?: string | null; + desactivationDate?: string | null; + evaluations: Evaluation[]; + goals: Goal[]; + results: Result[]; +} + +type SocialIssue = any; +type Goal = any; +type Result = any; +type Evaluation = any; +type AccompanyingPeriod = any; +type AccompanyingPeriodWorkEvaluation = any; +type AccompanyingPeriodWorkGoal = any; +type PrivateCommentEmbeddable = any; +type AccompanyingPeriodWorkReferrerHistory = any; diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/public/types.ts b/src/Bundle/ChillThirdPartyBundle/Resources/public/types.ts new file mode 100644 index 000000000..ccae6bbfd --- /dev/null +++ b/src/Bundle/ChillThirdPartyBundle/Resources/public/types.ts @@ -0,0 +1 @@ +export type Thirdparty = any; From 0d0f3528e2713520789bbcf914dce3de4c5ed571 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 13 Feb 2025 16:43:39 +0100 Subject: [PATCH 05/50] Add (temporary) types in Main and ThirdpartyBundle --- src/Bundle/ChillMainBundle/Resources/public/types.ts | 2 ++ .../ChillThirdPartyBundle/Resources/public/vuejs/types.ts | 1 + 2 files changed, 3 insertions(+) create mode 100644 src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/types.ts diff --git a/src/Bundle/ChillMainBundle/Resources/public/types.ts b/src/Bundle/ChillMainBundle/Resources/public/types.ts index b7b62980b..dd9b73dff 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/types.ts +++ b/src/Bundle/ChillMainBundle/Resources/public/types.ts @@ -203,3 +203,5 @@ export interface WorkflowAttachment { updatedBy: User | null; genericDoc: null | GenericDoc; } + +export type PrivateCommentEmbeddable = any; diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/types.ts b/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/types.ts new file mode 100644 index 000000000..b0f634d18 --- /dev/null +++ b/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/types.ts @@ -0,0 +1 @@ +export type ThirdParty = any; From 49d1f780012d653c66005ca8adc124a4b57d7d4a Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Mon, 17 Feb 2025 09:21:29 +0100 Subject: [PATCH 06/50] WIP fusion accompanyingperiodwork: controller, form, templates --- ...ompanyingPeriodWorkDuplicateController.php | 77 +++++++++++++++++++ .../Form/FindAccompanyingPeriodWorkType.php | 29 +++++++ .../PickAccompanyingPeriodWorkDynamicType.php | 49 ++++++++++++ .../AccompanyingPeriodWorkRenderBox.vue | 22 ++++++ .../assign_acpw_duplicate.html.twig | 38 +++++++++ 5 files changed, 215 insertions(+) create mode 100644 src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php create mode 100644 src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php create mode 100644 src/Bundle/ChillPersonBundle/Form/Type/PickAccompanyingPeriodWorkDynamicType.php create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue create mode 100644 src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php new file mode 100644 index 000000000..321b1812a --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php @@ -0,0 +1,77 @@ +accompanyingPeriodWorkRepository->find($id); + + if (null === $acpw1) { + throw $this->createNotFoundException("Accompanying period work with id {$id} not".' found on this server'); + } + + $this->denyAccessUnlessGranted( + 'CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', + $acpw1, + 'You are not allowed to merge this accompanying period work' + ); + + $form = $this->createForm(FindAccompanyingPeriodWorkType::class); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $acpw2 = $form->get('person')->getData(); + + // Validation: Ensure person1 is not the same as person2 + if ($acpw1->getId() === $acpw2->getId()) { + $this->addFlash('error', $this->translator->trans('The entities you are trying to merge cannot be the same')); + + return $this->redirectToRoute('chill_person_accompanying_period_work_show', ['id' => $acpw1->getId()]); + } + + $direction = $form->get('direction')->getData(); + + if ('starting' === $direction) { + $params = [ + 'acpw1_id' => $acpw1->getId(), + 'acpw2_id' => $acpw2->getId(), + ]; + } else { + $params = [ + 'acpw1_id' => $acpw2->getId(), + 'acpw2_id' => $acpw1->getId(), + ]; + } + +// return $this->redirectToRoute('chill_person_acpw_duplicate_confirm', $params); + } + + return $this->render('@ChillPerson/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig', [ + 'accompanyingCourse' => $acpw1->getAccompanyingPeriod(), + 'acpw' => $acpw1, + 'form' => $form->createView(), + ]); + } +} diff --git a/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php b/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php new file mode 100644 index 000000000..69ade244b --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php @@ -0,0 +1,29 @@ +add('acpw', PickAccompanyingPeriodWorkDynamicType::class) + ->add('direction', HiddenType::class, [ + 'data' => 'starting', + ]); + } +} diff --git a/src/Bundle/ChillPersonBundle/Form/Type/PickAccompanyingPeriodWorkDynamicType.php b/src/Bundle/ChillPersonBundle/Form/Type/PickAccompanyingPeriodWorkDynamicType.php new file mode 100644 index 000000000..8936b41c6 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Form/Type/PickAccompanyingPeriodWorkDynamicType.php @@ -0,0 +1,49 @@ +addViewTransformer(new EntityToJsonTransformer($this->denormalizer, $this->serializer, $options['multiple'], 'accompanyingPeriodWork')); + } + + public function buildView(FormView $view, FormInterface $form, array $options) + { + $view->vars['types'] = ['accompanyingPeriodWork']; + $view->vars['uniqid'] = uniqid('pick_acpw_dyn'); + $view->vars['as_id'] = true === $options['as_id'] ? '1' : '0'; + $view->vars['submit_on_adding_new_entity'] = true === $options['submit_on_adding_new_entity'] ? '1' : '0'; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver + ->setDefault('multiple', false) + ->setAllowedTypes('multiple', ['bool']) + ->setDefault('compound', false) + ->setDefault('suggested', []) + ->setDefault('as_id', false) + ->setAllowedTypes('as_id', ['bool']) + ->setDefault('submit_on_adding_new_entity', false) + ->setAllowedTypes('submit_on_adding_new_entity', ['bool']); + } + + public function getBlockPrefix() + { + return 'pick_entity_dynamic'; + } + +} diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue new file mode 100644 index 000000000..c1b13b319 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig new file mode 100644 index 000000000..7a3467f34 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig @@ -0,0 +1,38 @@ +{% extends '@ChillPerson/AccompanyingCourse/layout.html.twig' %} + +{% set activeRouteKey = 'chill_person_accompanying_period_work_assign_duplicate' %} + +{% block title %}{{ 'Assign an accompanying period work duplicate' }}{% endblock %} + + +{% block content %} +
+ +

{{ 'Assign an accompanying period work duplicate'|trans }}

+ + {{ form_start(form) }} + {{ form_rest(form) }} + + + + {{ form_end(form) }} + +
+{% endblock %} + +{% block js %} + {{ encore_entry_script_tags('mod_pickentity_type') }} +{% endblock %} + +{% block css %} + {{ encore_entry_link_tags('mod_pickentity_type') }} +{% endblock %} From 81ef64a246002e604cdec735ec082c476c454b8e Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 19 Feb 2025 15:55:24 +0100 Subject: [PATCH 07/50] WIP dynamic picking of accompanying period work --- .../Resources/public/vuejs/PickEntity/i18n.js | 2 ++ ...ompanyingPeriodWorkDuplicateController.php | 5 +++-- .../Form/FindAccompanyingPeriodWorkType.php | 21 ++++++++++++++++++- .../PickAccompanyingPeriodWorkDynamicType.php | 15 +++++++++---- .../AccompanyingCourseWork/show.html.twig | 3 +++ 5 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/PickEntity/i18n.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/PickEntity/i18n.js index 8502bf53e..f41dd882b 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/PickEntity/i18n.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/PickEntity/i18n.js @@ -11,10 +11,12 @@ const appMessages = { user: "Utilisateurs", person: "Usagers", thirdparty: "Tiers", + acpw: "Action d'accompagnements", modal_title_one: "Indiquer un ", user_one: "Utilisateur", thirdparty_one: "Tiers", person_one: "Usager", + acpw_one: "Action d'accompagnement" }, }, }; diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php index 321b1812a..c20340577 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php @@ -23,9 +23,10 @@ class AccompanyingPeriodWorkDuplicateController extends AbstractController public function __construct(private readonly AccompanyingPeriodWorkRepository $accompanyingPeriodWorkRepository, private readonly TranslatorInterface $translator) {} #[Route(path: '{_locale}/person/accompanying-period/work/{id}/assign-duplicate', name: 'chill_person_accompanying_period_work_assign_duplicate', methods: ['GET'])] - public function assignDuplicate(mixed $id, Request $request) + public function assignDuplicate(int $id, Request $request) { $acpw1= $this->accompanyingPeriodWorkRepository->find($id); + $accompanyingPeriod = $acpw1->getAccompanyingPeriod(); if (null === $acpw1) { throw $this->createNotFoundException("Accompanying period work with id {$id} not".' found on this server'); @@ -37,7 +38,7 @@ class AccompanyingPeriodWorkDuplicateController extends AbstractController 'You are not allowed to merge this accompanying period work' ); - $form = $this->createForm(FindAccompanyingPeriodWorkType::class); + $form = $this->createForm(FindAccompanyingPeriodWorkType::class, null, ['accompanyingPeriod' => $accompanyingPeriod]); $form->handleRequest($request); diff --git a/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php b/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php index 69ade244b..d38a0fbd9 100644 --- a/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php +++ b/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php @@ -11,7 +11,9 @@ declare(strict_types=1); namespace Chill\PersonBundle\Form; +use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Form\Type\PickAccompanyingPeriodWorkDynamicType; +use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\FormBuilderInterface; @@ -19,11 +21,28 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class FindAccompanyingPeriodWorkType extends AbstractType { + public function __construct(private readonly AccompanyingPeriodWorkRepository $repository) + { + } public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('acpw', PickAccompanyingPeriodWorkDynamicType::class) + $accompanyingPeriod = $options['accompanyingPeriod']; + $suggestedAcpw = $this->repository->findByAccompanyingPeriod($accompanyingPeriod); + + $builder + ->add('acpw', PickAccompanyingPeriodWorkDynamicType::class, [ + 'label' => 'Accompanying period work', + 'suggested' => $suggestedAcpw + ]) ->add('direction', HiddenType::class, [ 'data' => 'starting', ]); } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver + ->setRequired('accompanyingPeriod') + ->setAllowedTypes('accompanyingPeriod', AccompanyingPeriod::class); + } } diff --git a/src/Bundle/ChillPersonBundle/Form/Type/PickAccompanyingPeriodWorkDynamicType.php b/src/Bundle/ChillPersonBundle/Form/Type/PickAccompanyingPeriodWorkDynamicType.php index 8936b41c6..d08a1c061 100644 --- a/src/Bundle/ChillPersonBundle/Form/Type/PickAccompanyingPeriodWorkDynamicType.php +++ b/src/Bundle/ChillPersonBundle/Form/Type/PickAccompanyingPeriodWorkDynamicType.php @@ -9,23 +9,30 @@ use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\SerializerInterface; class PickAccompanyingPeriodWorkDynamicType extends AbstractType { - public function __construct(private readonly DenormalizerInterface $denormalizer, private readonly SerializerInterface $serializer) {} + public function __construct(private readonly DenormalizerInterface $denormalizer, private readonly SerializerInterface $serializer, private readonly NormalizerInterface $normalizer) {} public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->addViewTransformer(new EntityToJsonTransformer($this->denormalizer, $this->serializer, $options['multiple'], 'accompanyingPeriodWork')); + $builder->addViewTransformer(new EntityToJsonTransformer($this->denormalizer, $this->serializer, $options['multiple'], 'person')); } public function buildView(FormView $view, FormInterface $form, array $options) { - $view->vars['types'] = ['accompanyingPeriodWork']; + $view->vars['multiple'] = $options['multiple']; + $view->vars['types'] = ['acpw']; $view->vars['uniqid'] = uniqid('pick_acpw_dyn'); + $view->vars['suggested'] = []; $view->vars['as_id'] = true === $options['as_id'] ? '1' : '0'; - $view->vars['submit_on_adding_new_entity'] = true === $options['submit_on_adding_new_entity'] ? '1' : '0'; + $view->vars['submit_on_adding_new_entity'] = false; + + foreach ($options['suggested'] as $person) { + $view->vars['suggested'][] = $this->normalizer->normalize($person, 'json', ['groups' => 'read']); + } } public function configureOptions(OptionsResolver $resolver) diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/show.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/show.html.twig index 438a6fb7f..0ec14c367 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/show.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/show.html.twig @@ -68,6 +68,9 @@ {% endif %} +
  • + {{ 'Merge'|trans }} +
  • {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', work) %}
  • Date: Mon, 24 Feb 2025 12:34:32 +0100 Subject: [PATCH 08/50] WIP create new picker for accompanying period works --- .../Resources/views/Form/fields.html.twig | 21 +++++++++++++++++++ .../Form/FindAccompanyingPeriodWorkType.php | 6 ++++-- ... PickLinkedAccompanyingPeriodWorkType.php} | 15 +++++-------- 3 files changed, 30 insertions(+), 12 deletions(-) rename src/Bundle/ChillPersonBundle/Form/Type/{PickAccompanyingPeriodWorkDynamicType.php => PickLinkedAccompanyingPeriodWorkType.php} (71%) diff --git a/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig index 15794b9f7..9f07b3aa0 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig @@ -266,6 +266,27 @@ data-label="{{ form.vars['label']|trans|escape('html_attr') }}"> {% endblock %} +{% block pick_linked_entities_row %} +
    +
    + {{ form_label(form) }} + {{ form_help(form) }} +
    +
    +
    +
    + {{ form_widget(form) }} +
    +
    +{% endblock %} + +{% block pick_linked_entities_widget %} + +
    +{% endblock %} + {% block pick_postal_code_widget %} {{ form_help(form)}} diff --git a/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php b/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php index d38a0fbd9..c5ffa5406 100644 --- a/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php +++ b/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php @@ -13,6 +13,7 @@ namespace Chill\PersonBundle\Form; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Form\Type\PickAccompanyingPeriodWorkDynamicType; +use Chill\PersonBundle\Form\Type\PickLinkedAccompanyingPeriodWorkType; use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\HiddenType; @@ -30,9 +31,10 @@ class FindAccompanyingPeriodWorkType extends AbstractType $suggestedAcpw = $this->repository->findByAccompanyingPeriod($accompanyingPeriod); $builder - ->add('acpw', PickAccompanyingPeriodWorkDynamicType::class, [ + ->add('acpw', PickLinkedAccompanyingPeriodWorkType::class, [ 'label' => 'Accompanying period work', - 'suggested' => $suggestedAcpw + 'suggested' => $suggestedAcpw, + 'multiple' => false, ]) ->add('direction', HiddenType::class, [ 'data' => 'starting', diff --git a/src/Bundle/ChillPersonBundle/Form/Type/PickAccompanyingPeriodWorkDynamicType.php b/src/Bundle/ChillPersonBundle/Form/Type/PickLinkedAccompanyingPeriodWorkType.php similarity index 71% rename from src/Bundle/ChillPersonBundle/Form/Type/PickAccompanyingPeriodWorkDynamicType.php rename to src/Bundle/ChillPersonBundle/Form/Type/PickLinkedAccompanyingPeriodWorkType.php index d08a1c061..5b0e9a7dc 100644 --- a/src/Bundle/ChillPersonBundle/Form/Type/PickAccompanyingPeriodWorkDynamicType.php +++ b/src/Bundle/ChillPersonBundle/Form/Type/PickLinkedAccompanyingPeriodWorkType.php @@ -12,14 +12,9 @@ use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\SerializerInterface; -class PickAccompanyingPeriodWorkDynamicType extends AbstractType +class PickLinkedAccompanyingPeriodWorkType extends AbstractType { - public function __construct(private readonly DenormalizerInterface $denormalizer, private readonly SerializerInterface $serializer, private readonly NormalizerInterface $normalizer) {} - - public function buildForm(FormBuilderInterface $builder, array $options) - { - $builder->addViewTransformer(new EntityToJsonTransformer($this->denormalizer, $this->serializer, $options['multiple'], 'person')); - } + public function __construct(private readonly NormalizerInterface $normalizer) {} public function buildView(FormView $view, FormInterface $form, array $options) { @@ -30,8 +25,8 @@ class PickAccompanyingPeriodWorkDynamicType extends AbstractType $view->vars['as_id'] = true === $options['as_id'] ? '1' : '0'; $view->vars['submit_on_adding_new_entity'] = false; - foreach ($options['suggested'] as $person) { - $view->vars['suggested'][] = $this->normalizer->normalize($person, 'json', ['groups' => 'read']); + foreach ($options['suggested'] as $suggestion) { + $view->vars['suggested'][] = $this->normalizer->normalize($suggestion, 'json', ['groups' => 'read']); } } @@ -50,7 +45,7 @@ class PickAccompanyingPeriodWorkDynamicType extends AbstractType public function getBlockPrefix() { - return 'pick_entity_dynamic'; + return 'pick_linked_entities'; } } From 7682d81d5095e1efb9a80928dd3f14705620b0f0 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 27 Feb 2025 11:25:18 +0100 Subject: [PATCH 09/50] Different approach to creating acpw selector --- .../Resources/views/Form/fields.html.twig | 21 -------- ...ompanyingPeriodWorkDuplicateController.php | 39 ++++++++------ .../Form/FindAccompanyingPeriodWorkType.php | 4 +- .../PickLinkedAccompanyingPeriodWorkType.php | 51 ------------------- .../AccompanyingPeriodWorkSelector.js | 12 +++++ .../AccompanyingPeriodWorkSelector.vue | 33 ++++++++++++ .../AccompanyingPeriodWorkRenderBox.vue | 46 ++++++++++++----- .../assign_acpw_duplicate.html.twig | 8 +-- .../ChillPersonBundle/chill.webpack.config.js | 6 ++- 9 files changed, 112 insertions(+), 108 deletions(-) delete mode 100644 src/Bundle/ChillPersonBundle/Form/Type/PickLinkedAccompanyingPeriodWorkType.php create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelector.vue diff --git a/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig index 9f07b3aa0..15794b9f7 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig @@ -266,27 +266,6 @@ data-label="{{ form.vars['label']|trans|escape('html_attr') }}"> {% endblock %} -{% block pick_linked_entities_row %} -
    -
    - {{ form_label(form) }} - {{ form_help(form) }} -
    -
    -
    -
    - {{ form_widget(form) }} -
    -
    -{% endblock %} - -{% block pick_linked_entities_widget %} - -
    -{% endblock %} - {% block pick_postal_code_widget %} {{ form_help(form)}} diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php index c20340577..03ab458ab 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php @@ -11,30 +11,38 @@ declare(strict_types=1); namespace Chill\PersonBundle\Controller; +use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; use Chill\PersonBundle\Form\FindAccompanyingPeriodWorkType; use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Serializer\Serializer; +use Symfony\Component\Serializer\SerializerInterface; use Symfony\Contracts\Translation\TranslatorInterface; - +use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; class AccompanyingPeriodWorkDuplicateController extends AbstractController { - public function __construct(private readonly AccompanyingPeriodWorkRepository $accompanyingPeriodWorkRepository, private readonly TranslatorInterface $translator) {} + public function __construct(private readonly AccompanyingPeriodWorkRepository $accompanyingPeriodWorkRepository, private readonly TranslatorInterface $translator, private readonly SerializerInterface $serializer) {} + /** + * @ParamConverter("accompanyingPeriodWork", options={"id": "acpw_id"}) + */ #[Route(path: '{_locale}/person/accompanying-period/work/{id}/assign-duplicate', name: 'chill_person_accompanying_period_work_assign_duplicate', methods: ['GET'])] - public function assignDuplicate(int $id, Request $request) + public function assignDuplicate(AccompanyingPeriodWork $acpw, Request $request) { - $acpw1= $this->accompanyingPeriodWorkRepository->find($id); - $accompanyingPeriod = $acpw1->getAccompanyingPeriod(); + $accompanyingPeriod = $acpw->getAccompanyingPeriod(); - if (null === $acpw1) { - throw $this->createNotFoundException("Accompanying period work with id {$id} not".' found on this server'); - } + $acpwList = $this->accompanyingPeriodWorkRepository->findByAccompanyingPeriod($accompanyingPeriod); + + $acpwListArray = $this->serializer->normalize($acpwList, 'json', ['groups' => ['read']]); + $acpwListJson = json_encode($acpwListArray); + + dump($acpwListJson); $this->denyAccessUnlessGranted( 'CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', - $acpw1, + $acpw, 'You are not allowed to merge this accompanying period work' ); @@ -46,23 +54,23 @@ class AccompanyingPeriodWorkDuplicateController extends AbstractController $acpw2 = $form->get('person')->getData(); // Validation: Ensure person1 is not the same as person2 - if ($acpw1->getId() === $acpw2->getId()) { + if ($acpw->getId() === $acpw2->getId()) { $this->addFlash('error', $this->translator->trans('The entities you are trying to merge cannot be the same')); - return $this->redirectToRoute('chill_person_accompanying_period_work_show', ['id' => $acpw1->getId()]); + return $this->redirectToRoute('chill_person_accompanying_period_work_show', ['id' => $acpw->getId()]); } $direction = $form->get('direction')->getData(); if ('starting' === $direction) { $params = [ - 'acpw1_id' => $acpw1->getId(), + 'acpw1_id' => $acpw->getId(), 'acpw2_id' => $acpw2->getId(), ]; } else { $params = [ 'acpw1_id' => $acpw2->getId(), - 'acpw2_id' => $acpw1->getId(), + 'acpw2_id' => $acpw->getId(), ]; } @@ -70,8 +78,9 @@ class AccompanyingPeriodWorkDuplicateController extends AbstractController } return $this->render('@ChillPerson/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig', [ - 'accompanyingCourse' => $acpw1->getAccompanyingPeriod(), - 'acpw' => $acpw1, + 'accompanyingCourse' => $acpw->getAccompanyingPeriod(), + 'acpwListJson' => $acpwListJson, + 'acpw' => $acpw, 'form' => $form->createView(), ]); } diff --git a/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php b/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php index c5ffa5406..1fd856e0b 100644 --- a/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php +++ b/src/Bundle/ChillPersonBundle/Form/FindAccompanyingPeriodWorkType.php @@ -31,10 +31,8 @@ class FindAccompanyingPeriodWorkType extends AbstractType $suggestedAcpw = $this->repository->findByAccompanyingPeriod($accompanyingPeriod); $builder - ->add('acpw', PickLinkedAccompanyingPeriodWorkType::class, [ + ->add('acpw', HiddenType::class, [ 'label' => 'Accompanying period work', - 'suggested' => $suggestedAcpw, - 'multiple' => false, ]) ->add('direction', HiddenType::class, [ 'data' => 'starting', diff --git a/src/Bundle/ChillPersonBundle/Form/Type/PickLinkedAccompanyingPeriodWorkType.php b/src/Bundle/ChillPersonBundle/Form/Type/PickLinkedAccompanyingPeriodWorkType.php deleted file mode 100644 index 5b0e9a7dc..000000000 --- a/src/Bundle/ChillPersonBundle/Form/Type/PickLinkedAccompanyingPeriodWorkType.php +++ /dev/null @@ -1,51 +0,0 @@ -vars['multiple'] = $options['multiple']; - $view->vars['types'] = ['acpw']; - $view->vars['uniqid'] = uniqid('pick_acpw_dyn'); - $view->vars['suggested'] = []; - $view->vars['as_id'] = true === $options['as_id'] ? '1' : '0'; - $view->vars['submit_on_adding_new_entity'] = false; - - foreach ($options['suggested'] as $suggestion) { - $view->vars['suggested'][] = $this->normalizer->normalize($suggestion, 'json', ['groups' => 'read']); - } - } - - public function configureOptions(OptionsResolver $resolver) - { - $resolver - ->setDefault('multiple', false) - ->setAllowedTypes('multiple', ['bool']) - ->setDefault('compound', false) - ->setDefault('suggested', []) - ->setDefault('as_id', false) - ->setAllowedTypes('as_id', ['bool']) - ->setDefault('submit_on_adding_new_entity', false) - ->setAllowedTypes('submit_on_adding_new_entity', ['bool']); - } - - public function getBlockPrefix() - { - return 'pick_linked_entities'; - } - -} diff --git a/src/Bundle/ChillPersonBundle/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js b/src/Bundle/ChillPersonBundle/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js new file mode 100644 index 000000000..3ec34b7a4 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js @@ -0,0 +1,12 @@ +import { createApp } from 'vue'; +import AccompanyingPeriodWorkSelector from "../../vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelector.vue"; + + +document.addEventListener("DOMContentLoaded", () => { + const el = document.getElementById('linked-acpw-selector'); + if (el) { + createApp(AccompanyingPeriodWorkSelector, { + acpwList: JSON.parse(el.dataset.acpwList) + }).mount(el); + } +}); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelector.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelector.vue new file mode 100644 index 000000000..579b9f638 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelector.vue @@ -0,0 +1,33 @@ + + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue index c1b13b319..a596b02fe 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue @@ -1,22 +1,42 @@ + diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig index 7a3467f34..c0d142626 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig @@ -9,8 +9,10 @@

    {{ 'Assign an accompanying period work duplicate'|trans }}

    - {{ form_start(form) }} + {%- if form.acpw is defined -%} +
    + {% endif %} {{ form_rest(form) }}
      @@ -30,9 +32,9 @@ {% endblock %} {% block js %} - {{ encore_entry_script_tags('mod_pickentity_type') }} + {{ encore_entry_script_tags('mod_duplicate_selector') }} {% endblock %} {% block css %} - {{ encore_entry_link_tags('mod_pickentity_type') }} + {{ encore_entry_link_tags('mod_duplicate_selector') }} {% endblock %} diff --git a/src/Bundle/ChillPersonBundle/chill.webpack.config.js b/src/Bundle/ChillPersonBundle/chill.webpack.config.js index e4c6ed3af..4c8f106c4 100644 --- a/src/Bundle/ChillPersonBundle/chill.webpack.config.js +++ b/src/Bundle/ChillPersonBundle/chill.webpack.config.js @@ -6,7 +6,6 @@ module.exports = function (encore, entries) { encore.addAliases({ ChillPersonAssets: __dirname + "/Resources/public", }); - encore.addEntry( "vue_household_members_editor", __dirname + "/Resources/public/vuejs/HouseholdMembersEditor/index.js", @@ -31,7 +30,6 @@ module.exports = function (encore, entries) { "vue_export_action_goal_result", __dirname + "/Resources/public/vuejs/ExportFormActionGoalResult/index.js", ); - encore.addEntry( "mod_set_referrer", __dirname + "/Resources/public/mod/AccompanyingPeriod/setReferrer.js", @@ -66,4 +64,8 @@ module.exports = function (encore, entries) { "page_create_person", __dirname + "/Resources/public/page/person/create-person.js", ); + encore.addEntry( + "mod_duplicate_selector", + __dirname + "/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js", + ); }; From 9e8cf60dd8223dd00cfd6b82ea51c08b9a61a70f Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 4 Mar 2025 19:12:18 +0100 Subject: [PATCH 10/50] Open modal to select acpw --- ...ompanyingPeriodWorkDuplicateController.php | 23 ++++++---- .../AccompanyingPeriodWorkSelector.js | 12 ++--- .../Resources/public/types.ts | 2 +- .../AccompanyingPeriodWorkSelector.vue | 28 ++++------- .../AccompanyingPeriodWorkSelectorModal.vue | 46 +++++++++++++++++++ .../AccompanyingPeriodWorkRenderBox.vue | 12 +---- .../assign_acpw_duplicate.html.twig | 5 +- 7 files changed, 79 insertions(+), 49 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelectorModal.vue diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php index 03ab458ab..2d77d0f51 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php @@ -11,19 +11,18 @@ declare(strict_types=1); namespace Chill\PersonBundle\Controller; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; use Chill\PersonBundle\Form\FindAccompanyingPeriodWorkType; use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Serializer\Serializer; -use Symfony\Component\Serializer\SerializerInterface; use Symfony\Contracts\Translation\TranslatorInterface; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; class AccompanyingPeriodWorkDuplicateController extends AbstractController { - public function __construct(private readonly AccompanyingPeriodWorkRepository $accompanyingPeriodWorkRepository, private readonly TranslatorInterface $translator, private readonly SerializerInterface $serializer) {} + public function __construct(private readonly AccompanyingPeriodWorkRepository $accompanyingPeriodWorkRepository, private readonly TranslatorInterface $translator, private readonly TranslatableStringHelperInterface $stringHelper) {} /** * @ParamConverter("accompanyingPeriodWork", options={"id": "acpw_id"}) @@ -35,10 +34,14 @@ class AccompanyingPeriodWorkDuplicateController extends AbstractController $acpwList = $this->accompanyingPeriodWorkRepository->findByAccompanyingPeriod($accompanyingPeriod); - $acpwListArray = $this->serializer->normalize($acpwList, 'json', ['groups' => ['read']]); - $acpwListJson = json_encode($acpwListArray); - - dump($acpwListJson); + $acpwArray = array_map(function ($acpw) { + return [ + 'id' => $acpw->getId(), + 'socialAction' => $this->stringHelper->localize($acpw->getSocialAction()->getTitle()), + 'start_date' => $acpw->getStartDate(), + 'end_date' => $acpw->getEndDate(), + ]; + }, $acpwList); $this->denyAccessUnlessGranted( 'CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', @@ -62,7 +65,7 @@ class AccompanyingPeriodWorkDuplicateController extends AbstractController $direction = $form->get('direction')->getData(); - if ('starting' === $direction) { +/* if ('starting' === $direction) { $params = [ 'acpw1_id' => $acpw->getId(), 'acpw2_id' => $acpw2->getId(), @@ -72,14 +75,14 @@ class AccompanyingPeriodWorkDuplicateController extends AbstractController 'acpw1_id' => $acpw2->getId(), 'acpw2_id' => $acpw->getId(), ]; - } + }*/ // return $this->redirectToRoute('chill_person_acpw_duplicate_confirm', $params); } return $this->render('@ChillPerson/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig', [ 'accompanyingCourse' => $acpw->getAccompanyingPeriod(), - 'acpwListJson' => $acpwListJson, + 'acpwList' => $acpwArray, 'acpw' => $acpw, 'form' => $form->createView(), ]); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js b/src/Bundle/ChillPersonBundle/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js index 3ec34b7a4..05cd5a9b3 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js @@ -1,12 +1,10 @@ import { createApp } from 'vue'; -import AccompanyingPeriodWorkSelector from "../../vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelector.vue"; - +import AccompanyingPeriodWorkSelectorModal from "../../vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelectorModal.vue"; document.addEventListener("DOMContentLoaded", () => { - const el = document.getElementById('linked-acpw-selector'); - if (el) { - createApp(AccompanyingPeriodWorkSelector, { - acpwList: JSON.parse(el.dataset.acpwList) - }).mount(el); + const el = document.getElementById('linked-acpw-selector'); + if (el) { + const acpwList = JSON.parse(el.dataset.acpwList); + createApp(AccompanyingPeriodWorkSelectorModal, { acpwList }).mount(el); } }); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/types.ts b/src/Bundle/ChillPersonBundle/Resources/public/types.ts index c93440d75..0b7867370 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/types.ts +++ b/src/Bundle/ChillPersonBundle/Resources/public/types.ts @@ -59,7 +59,7 @@ export interface AccompanyingPeriodWork { privateComment: PrivateCommentEmbeddable; referrersHistory: AccompanyingPeriodWorkReferrerHistory[]; results: Result[]; - socialAction?: SocialAction; + socialAction: SocialAction; startDate?: string; thirdParties: Thirdparty[]; updatedAt?: string; diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelector.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelector.vue index 579b9f638..4ee4d58c9 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelector.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelector.vue @@ -1,33 +1,25 @@ + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelectorModal.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelectorModal.vue new file mode 100644 index 000000000..0c676101b --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelectorModal.vue @@ -0,0 +1,46 @@ + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue index a596b02fe..728ac8923 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue @@ -1,20 +1,12 @@ diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig index c0d142626..84f20481f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriodWorkDuplicate/assign_acpw_duplicate.html.twig @@ -4,14 +4,13 @@ {% block title %}{{ 'Assign an accompanying period work duplicate' }}{% endblock %} - {% block content %}
      -

      {{ 'Assign an accompanying period work duplicate'|trans }}

      +

      {{ 'acpw_duplicate.Assign duplicate'|trans }}

      {{ form_start(form) }} {%- if form.acpw is defined -%} -
      +
      {% endif %} {{ form_rest(form) }} From a52aac2d98b4833f4a46a1b38bf00a640bc2eeca Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 5 Mar 2025 10:11:54 +0100 Subject: [PATCH 11/50] Update package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 9493bd5dc..15697def7 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "@hotwired/stimulus": "^3.0.0", "@luminateone/eslint-baseline": "^1.0.9", "@symfony/stimulus-bridge": "^3.2.0", + "@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets", "@symfony/webpack-encore": "^4.1.0", "@tsconfig/node20": "^20.1.4", "@types/dompurify": "^3.0.5", From e253d1b27611ed1f32837e3c20faf16efe1b60af Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 5 Mar 2025 12:27:48 +0100 Subject: [PATCH 12/50] Styling and organization of components --- ...ompanyingPeriodWorkDuplicateController.php | 4 +- .../AccompanyingPeriodWorkSelector.js | 2 +- .../AccompanyingPeriodWorkItem.vue | 48 +++++++++++++++++++ .../AccompanyingPeriodWorkList.vue | 32 +++++++++++++ .../AccompanyingPeriodWorkSelectorModal.vue | 22 +++++---- .../AccompanyingPeriodWorkSelector.vue | 25 ---------- .../AccompanyingPeriodWorkRenderBox.vue | 34 ------------- .../translations/messages.fr.yml | 4 ++ 8 files changed, 100 insertions(+), 71 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkItem.vue create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkList.vue rename src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/{DuplicateSelector => AccompanyingPeriodWorkSelector}/AccompanyingPeriodWorkSelectorModal.vue (58%) delete mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelector.vue delete mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Entity/AccompanyingPeriodWorkRenderBox.vue diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php index 2d77d0f51..0b557b173 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkDuplicateController.php @@ -38,8 +38,8 @@ class AccompanyingPeriodWorkDuplicateController extends AbstractController return [ 'id' => $acpw->getId(), 'socialAction' => $this->stringHelper->localize($acpw->getSocialAction()->getTitle()), - 'start_date' => $acpw->getStartDate(), - 'end_date' => $acpw->getEndDate(), + 'startDate' => $acpw->getStartDate(), + 'endDate' => $acpw->getEndDate(), ]; }, $acpwList); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js b/src/Bundle/ChillPersonBundle/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js index 05cd5a9b3..7fd39b5bc 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js @@ -1,5 +1,5 @@ import { createApp } from 'vue'; -import AccompanyingPeriodWorkSelectorModal from "../../vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelectorModal.vue"; +import AccompanyingPeriodWorkSelectorModal from "../../vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkSelectorModal.vue"; document.addEventListener("DOMContentLoaded", () => { const el = document.getElementById('linked-acpw-selector'); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkItem.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkItem.vue new file mode 100644 index 000000000..0eb803ef9 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkItem.vue @@ -0,0 +1,48 @@ + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkList.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkList.vue new file mode 100644 index 000000000..3932034b1 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkList.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelectorModal.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkSelectorModal.vue similarity index 58% rename from src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelectorModal.vue rename to src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkSelectorModal.vue index 0c676101b..1fe207aaf 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/DuplicateSelector/AccompanyingPeriodWorkSelectorModal.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkSelectorModal.vue @@ -1,25 +1,28 @@