From 4e4d7cfc10bc930c64490a01a9cf0080606dc602 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 29 Apr 2025 14:31:39 +0200 Subject: [PATCH] Create address on the fly field in event form --- .../Controller/EventController.php | 6 ++ src/Bundle/ChillEventBundle/Entity/Event.php | 9 +++ .../ChillEventBundle/Form/EventType.php | 22 +++--- .../Resources/public/vuejs/App.vue | 14 ++++ .../Resources/public/vuejs/index.js | 6 ++ .../Resources/public/vuejs/store.js | 79 +++++++++++++++++++ .../Resources/views/Event/new.html.twig | 28 +++++-- .../ChillEventBundle/chill.webpack.config.js | 7 ++ .../vuejs/Address/components/AddAddress.vue | 68 ++++++++++------ .../components/AddAddress/AddressMore.vue | 58 ++++++++++---- .../AddAddress/AddressSelection.vue | 42 +++++++--- .../components/AddAddress/CitySelection.vue | 42 +++++++--- .../AddAddress/CountrySelection.vue | 28 +++++-- .../vuejs/Address/components/EditPane.vue | 21 ++++- .../vuejs/Address/components/ShowPane.vue | 56 +++++++++---- 15 files changed, 386 insertions(+), 100 deletions(-) create mode 100644 src/Bundle/ChillEventBundle/Resources/public/vuejs/App.vue create mode 100644 src/Bundle/ChillEventBundle/Resources/public/vuejs/index.js create mode 100644 src/Bundle/ChillEventBundle/Resources/public/vuejs/store.js diff --git a/src/Bundle/ChillEventBundle/Controller/EventController.php b/src/Bundle/ChillEventBundle/Controller/EventController.php index b4f099769..09cb86861 100644 --- a/src/Bundle/ChillEventBundle/Controller/EventController.php +++ b/src/Bundle/ChillEventBundle/Controller/EventController.php @@ -41,6 +41,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\Security\Core\Security; +use Symfony\Component\Serializer\SerializerInterface; use Symfony\Contracts\Translation\TranslatorInterface; /** @@ -59,6 +60,8 @@ final class EventController extends AbstractController private readonly PaginatorFactory $paginator, private readonly Security $security, private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry, + private readonly SerializerInterface $serializer, + ) {} #[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/event/event/{event_id}/delete', name: 'chill_event__event_delete', requirements: ['event_id' => '\d+'], methods: ['GET', 'POST', 'DELETE'])] @@ -202,9 +205,12 @@ final class EventController extends AbstractController return $this->redirectToRoute('chill_event__event_show', ['event_id' => $entity->getId()]); } + $entity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); + return $this->render('@ChillEvent/Event/new.html.twig', [ 'entity' => $entity, 'form' => $form->createView(), + 'entity_json' => $entity_array, ]); } diff --git a/src/Bundle/ChillEventBundle/Entity/Event.php b/src/Bundle/ChillEventBundle/Entity/Event.php index 28fcf6092..c45c68159 100644 --- a/src/Bundle/ChillEventBundle/Entity/Event.php +++ b/src/Bundle/ChillEventBundle/Entity/Event.php @@ -27,6 +27,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Serializer\Annotation as Serializer; /** * Class Event. @@ -58,6 +59,7 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter private ?User $moderator = null; #[Assert\NotBlank] + #[Serializer\Groups(['read'])] #[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 150)] private ?string $name = null; @@ -65,13 +67,19 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter * @var Collection */ #[ORM\OneToMany(mappedBy: 'event', targetEntity: Participation::class)] + #[Serializer\Groups(['read'])] private Collection $participations; #[Assert\NotNull] + #[Serializer\Groups(['read'])] #[ORM\ManyToOne(targetEntity: EventType::class)] private ?EventType $type = null; + /** + * @var Collection + */ #[ORM\ManyToMany(targetEntity: EventTheme::class)] + #[Serializer\Groups(['read'])] #[ORM\JoinTable('chill_event_eventtheme')] private Collection $themes; @@ -79,6 +87,7 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter private CommentEmbeddable $comment; #[ORM\ManyToOne(targetEntity: Location::class)] + #[Serializer\Groups(['read'])] #[ORM\JoinColumn(nullable: true)] private ?Location $location = null; diff --git a/src/Bundle/ChillEventBundle/Form/EventType.php b/src/Bundle/ChillEventBundle/Form/EventType.php index 77844aaba..6bceed93f 100644 --- a/src/Bundle/ChillEventBundle/Form/EventType.php +++ b/src/Bundle/ChillEventBundle/Form/EventType.php @@ -14,29 +14,27 @@ namespace Chill\EventBundle\Form; use Chill\DocStoreBundle\Entity\StoredObject; use Chill\DocStoreBundle\Form\StoredObjectType; use Chill\EventBundle\Entity\Event; -use Chill\EventBundle\Entity\EventTheme; use Chill\EventBundle\Form\Type\PickEventThemeType; use Chill\EventBundle\Form\Type\PickEventTypeType; -use Chill\EventBundle\Repository\EventThemeRepository; use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Form\DataTransformer\IdToLocationDataTransformer; use Chill\MainBundle\Form\Type\ChillCollectionType; use Chill\MainBundle\Form\Type\ChillDateTimeType; use Chill\MainBundle\Form\Type\CommentType; use Chill\MainBundle\Form\Type\PickUserDynamicType; -use Chill\MainBundle\Form\Type\PickUserLocationType; use Chill\MainBundle\Form\Type\ScopePickerType; -use Chill\MainBundle\Templating\TranslatableStringHelperInterface; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Extension\Core\Type\MoneyType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Contracts\Translation\TranslatorInterface; class EventType extends AbstractType { - public function __construct(private readonly EventThemeRepository $eventThemeRepository, private readonly TranslatorInterface $translator, private readonly TranslatableStringHelperInterface $translatableStringHelper) {} + public function __construct( + private readonly IdToLocationDataTransformer $idToLocationDataTransformer, + ) {} public function buildForm(FormBuilderInterface $builder, array $options) { @@ -63,9 +61,6 @@ class EventType extends AbstractType ->add('moderator', PickUserDynamicType::class, [ 'label' => 'Pick a moderator', ]) - ->add('location', PickUserLocationType::class, [ - 'label' => 'event.fields.location', - ]) ->add('comment', CommentType::class, [ 'label' => 'Comment', 'required' => false, @@ -85,6 +80,10 @@ class EventType extends AbstractType 'label' => 'event.fields.organizationCost', 'help' => 'event.form.organisationCost_help', ]); + + $builder->add('location', HiddenType::class) + ->get('location') + ->addModelTransformer($this->idToLocationDataTransformer); } public function configureOptions(OptionsResolver $resolver) @@ -103,6 +102,7 @@ class EventType extends AbstractType */ public function getBlockPrefix() { - return 'chill_eventbundle_event'; + // as the js shares some hardcoded items from the activity bundle, we have to rewrite block prefix + return 'chill_activitybundle_activity'; } } diff --git a/src/Bundle/ChillEventBundle/Resources/public/vuejs/App.vue b/src/Bundle/ChillEventBundle/Resources/public/vuejs/App.vue new file mode 100644 index 000000000..89158d742 --- /dev/null +++ b/src/Bundle/ChillEventBundle/Resources/public/vuejs/App.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/Bundle/ChillEventBundle/Resources/public/vuejs/index.js b/src/Bundle/ChillEventBundle/Resources/public/vuejs/index.js new file mode 100644 index 000000000..e0be75aaf --- /dev/null +++ b/src/Bundle/ChillEventBundle/Resources/public/vuejs/index.js @@ -0,0 +1,6 @@ +import { createApp } from "vue"; + +import App from "./App.vue"; +import store from "./store"; + +createApp(App).use(store).mount("#event"); diff --git a/src/Bundle/ChillEventBundle/Resources/public/vuejs/store.js b/src/Bundle/ChillEventBundle/Resources/public/vuejs/store.js new file mode 100644 index 000000000..ddfa3d512 --- /dev/null +++ b/src/Bundle/ChillEventBundle/Resources/public/vuejs/store.js @@ -0,0 +1,79 @@ +import "es6-promise/auto"; +import { createStore } from "vuex"; + +import prepareLocations from "ChillActivityAssets/vuejs/Activity/store.locations"; +import {whoami} from "ChillMainAssets/lib/api/user"; +import {mapEntity} from "ChillCalendarAssets/vuejs/Calendar/store/utils"; +import {postLocation} from "ChillActivityAssets/vuejs/Activity/api"; + +const debug = process.env.NODE_ENV !== "production"; + +const store = createStore({ + strict: debug, + state: { + activity: window.entity, // activity is the event entity in this case (re-using component from activity bundle) + currentEvent: null, + availableLocations: [], + me: null, + }, + getters: { + + }, + actions: { + addAvailableLocationGroup({ commit }, payload) { + commit("addAvailableLocationGroup", payload); + }, + updateLocation({ commit }, value) { + // console.log("### action: updateLocation", value); + let hiddenLocation = document.getElementById( + "chill_activitybundle_activity_location", + ); + if (value.onthefly) { + const body = { + type: "location", + name: + value.name === "__AccompanyingCourseLocation__" ? null : value.name, + locationType: { + id: value.locationType.id, + type: "location-type", + }, + }; + if (value.address.id) { + Object.assign(body, { + address: { + id: value.address.id, + }, + }); + } + postLocation(body) + .then((location) => (hiddenLocation.value = location.id)) + .catch((err) => { + console.log(err.message); + }); + } else { + hiddenLocation.value = value.id; + } + commit("updateLocation", value); + }, + }, + mutations: { + setWhoAmiI(state, me) { + state.me = me; + }, + addAvailableLocationGroup(state, group) { + state.availableLocations.push(group); + }, + updateLocation(state, value) { + // console.log("### mutation: updateLocation", value); + state.activity.location = value; + }, + } +}); + +whoami().then((me) => { + store.commit("setWhoAmiI", me); +}); + +prepareLocations(store); + +export default store; diff --git a/src/Bundle/ChillEventBundle/Resources/views/Event/new.html.twig b/src/Bundle/ChillEventBundle/Resources/views/Event/new.html.twig index 898af74c1..279bf4588 100644 --- a/src/Bundle/ChillEventBundle/Resources/views/Event/new.html.twig +++ b/src/Bundle/ChillEventBundle/Resources/views/Event/new.html.twig @@ -1,19 +1,19 @@ -{% extends '@ChillEvent/layout.html.twig' %} {% block js %} -{{ encore_entry_script_tags("mod_async_upload") }} -{{ encore_entry_script_tags("mod_pickentity_type") }} +{% extends '@ChillEvent/layout.html.twig' %} -{% endblock %} {% block css %} +{% block css %} {{ encore_entry_link_tags("mod_async_upload") }} {{ encore_entry_link_tags("mod_pickentity_type") }} +{{ encore_entry_link_tags('vue_event') }} +{% endblock %} -{% endblock %} {% block title 'Event creation'|trans %} {% block event_content --%} +{% block title 'Event creation'|trans %} + +{% block event_content -%}

{{ "Event creation" | trans }}

{{ form_start(form) }} {{ form_errors(form) }} -{# {{ form_row(form.circle) }}#} {{ form_row(form.name) }} {{ form_row(form.circle) }} {{ form_row(form.date) }} @@ -21,6 +21,7 @@ {{ form_row(form.themes) }} {{ form_row(form.moderator) }} {{ form_row(form.location) }} +
{{ form_row(form.organizationCost) }} {{ form_row(form.comment) }} {{ form_row(form.documents) }} @@ -42,5 +43,18 @@ {{ form_end(form) }} + +
+
{% endblock %} + +{% block js %} + {{ encore_entry_script_tags("mod_async_upload") }} + {{ encore_entry_script_tags("mod_pickentity_type") }} + {{ encore_entry_script_tags('vue_event') }} + +{% endblock %} diff --git a/src/Bundle/ChillEventBundle/chill.webpack.config.js b/src/Bundle/ChillEventBundle/chill.webpack.config.js index e2c1e14bc..3f13a7773 100644 --- a/src/Bundle/ChillEventBundle/chill.webpack.config.js +++ b/src/Bundle/ChillEventBundle/chill.webpack.config.js @@ -1,3 +1,10 @@ module.exports = function (encore, entries) { entries.push(__dirname + "/Resources/public/chill/index.js"); + + encore.addEntry( + "vue_event", + __dirname + "/Resources/public/vuejs/index.js", + ); }; + + diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue index 103849e3a..923defdeb 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue @@ -21,10 +21,10 @@ > @@ -43,7 +43,7 @@ @@ -62,13 +62,13 @@ > @@ -85,10 +85,10 @@ > @@ -108,17 +108,17 @@ @@ -139,7 +139,7 @@ > @@ -171,10 +171,10 @@ > @@ -193,10 +193,10 @@ @@ -216,13 +216,13 @@ @@ -244,9 +244,16 @@ import { postPostalCode, } from "../api"; import { - postAddressToPerson, - postAddressToHousehold, -} from "ChillPersonAssets/vuejs/_api/AddAddress.js"; + CREATE_A_NEW_ADDRESS, + ADDRESS_LOADING, + ACTIVITY_CREATE_ADDRESS, + ACTIVITY_EDIT_ADDRESS, + CANCEL, + SAVE, + PREVIOUS, + NEXT, + trans, +} from "translator"; import ShowPane from "./ShowPane.vue"; import SuggestPane from "./SuggestPane.vue"; import EditPane from "./EditPane.vue"; @@ -254,6 +261,17 @@ import DatePane from "./DatePane.vue"; export default { name: "AddAddress", + setup() { + return { + trans, + CREATE_A_NEW_ADDRESS, + ADDRESS_LOADING, + CANCEL, + SAVE, + PREVIOUS, + NEXT + }; + }, props: ["context", "options", "addressChangedCallback"], components: { Modal, @@ -373,9 +391,11 @@ export default { (this.options.title.edit !== null || this.options.title.create !== null) ) { + console.log('this.options.title', this.options.title) + return this.context.edit - ? this.options.title.edit - : this.options.title.create; + ? ACTIVITY_EDIT_ADDRESS + : ACTIVITY_CREATE_ADDRESS; } return this.context.edit ? this.defaultz.title.edit diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressMore.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressMore.vue index 4b59efbc6..0be4b7809 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressMore.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressMore.vue @@ -1,6 +1,6 @@