From 387bf55b11882005d5dec2e6e54d82f652473655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 5 Dec 2025 16:32:30 +0000 Subject: [PATCH 01/20] fix version constraint in chill-zimbra-bundle --- packages/ChillZimbraBundle/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ChillZimbraBundle/composer.json b/packages/ChillZimbraBundle/composer.json index f62e21125..4a53b3ed5 100644 --- a/packages/ChillZimbraBundle/composer.json +++ b/packages/ChillZimbraBundle/composer.json @@ -9,7 +9,7 @@ "social worker" ], "require": { - "chill-project/chill-bundles": "dev-master as v4.6.1", + "chill-project/chill-bundles": "^4.9.0", "zimbra-api/soap-api": "^3.2.2", "psr/http-client": "^1.0", "nyholm/psr7": "^1.0" From 53b02a0ced150bc098484b681aa9d00ecfdaa546 Mon Sep 17 00:00:00 2001 From: LenaertsJ Date: Mon, 8 Dec 2025 12:45:01 +0000 Subject: [PATCH 02/20] Improve the display of upcoming calendar items within the person render box --- .../ChillPersonBundle/Entity/Person.php | 36 +++++++++++++++- .../Resources/views/Entity/person.html.twig | 1 - .../views/Person/list_with_period.html.twig | 41 +++++++++++++++++++ 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index aa78774b6..2cdb99c54 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -43,6 +43,7 @@ use DateTime; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Criteria; +use Doctrine\Common\Collections\Order; use Doctrine\Common\Collections\ReadableCollection; use Doctrine\Common\Collections\Selectable; use Doctrine\ORM\Mapping as ORM; @@ -139,6 +140,12 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI #[ORM\ManyToMany(targetEntity: Calendar::class, mappedBy: 'persons')] private Collection $calendars; + /** + * @var Collection&Selectable + */ + #[ORM\OneToMany(mappedBy: 'person', targetEntity: Calendar::class)] + private Collection $directCalendars; + /** * The person's center. * @@ -406,6 +413,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI public function __construct() { $this->calendars = new ArrayCollection(); + $this->directCalendars = new ArrayCollection(); $this->accompanyingPeriodParticipations = new ArrayCollection(); $this->spokenLanguages = new ArrayCollection(); $this->addresses = new ArrayCollection(); @@ -866,6 +874,30 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI return $this->calendars; } + /** + * Get next calendars for this person (calendars with start date after today). + * Only returns calendars that are directly linked to this person via the person property, + * not those linked through AccompanyingPeriods. + * + * @param int|null $limit Optional limit for the number of results + * + * @return array + */ + public function getNextCalendarsForPerson(?int $limit = null): array + { + $today = new \DateTimeImmutable('today'); + + $criteria = Criteria::create() + ->where(Criteria::expr()->gte('startDate', $today)) + ->orderBy(['startDate' => Order::Ascending]); + + if (null !== $limit) { + $criteria->setMaxResults($limit); + } + + return $this->directCalendars->matching($criteria)->toArray(); + } + public function getCenter(): ?Center { if (null !== $this->centerCurrent) { @@ -1119,7 +1151,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI ->where( $expr->eq('shareHousehold', false) ) - ->orderBy(['startDate' => \Doctrine\Common\Collections\Order::Descending]); + ->orderBy(['startDate' => Order::Descending]); return $this->getHouseholdParticipations() ->matching($criteria); @@ -1141,7 +1173,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI ->where( $expr->eq('shareHousehold', true) ) - ->orderBy(['startDate' => \Doctrine\Common\Collections\Order::Descending, 'id' => \Doctrine\Common\Collections\Order::Descending]); + ->orderBy(['startDate' => Order::Descending, 'id' => Order::Descending]); return $this->getHouseholdParticipations() ->matching($criteria); diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Entity/person.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Entity/person.html.twig index 5572bd7b1..c373fd58b 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Entity/person.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Entity/person.html.twig @@ -212,4 +212,3 @@ {%- endif -%} - diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Person/list_with_period.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Person/list_with_period.html.twig index 0840cecb6..cf7fb1466 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Person/list_with_period.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Person/list_with_period.html.twig @@ -301,6 +301,47 @@ 'customButtons': { 'after': _self.button_person_after(person), 'before': _self.button_person_before((person)) } }) }} + {% set calendars = [] %} + {% for c in person.getNextCalendarsForPerson(10) %} + {% if is_granted('CHILL_CALENDAR_CALENDAR_SEE', c) %} + {% set calendars = calendars|merge([c]) %} + {% endif %} + {% endfor %} + + {% if calendars|length > 0 %} +
+
+
+

{{ 'chill_calendar.Next calendars'|trans }}

+
+
+
+ + {% if is_granted('CHILL_CALENDAR_CALENDAR_SEE', person) %} + + {% endif %} +
+
+
+
+ {% endif %} + {#- 'acps' is for AcCompanyingPeriodS #} {%- set acps = [] %} {%- set acpsClosed = [] %} From fc66d0e07020cd332e6bdc59f83334ef7fdcb0f5 Mon Sep 17 00:00:00 2001 From: Boris Waaub Date: Tue, 9 Dec 2025 10:42:36 +0100 Subject: [PATCH 03/20] =?UTF-8?q?FIX:=20Dans=20la=20modale=20d'accueil=20d?= =?UTF-8?q?u=20ticket,=20les=20boutons=20doivent=20=C3=AAtre=20dans=20le?= =?UTF-8?q?=20footer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Resources/public/vuejs/TicketApp/App.vue | 40 ++- .../components/TicketInitFormComponent.vue | 185 +++++------ .../src/translations/messages+intl-icu.fr.yml | 301 +++++++++--------- 3 files changed, 255 insertions(+), 271 deletions(-) diff --git a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/App.vue b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/App.vue index b2abb8276..0128d8866 100644 --- a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/App.vue +++ b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/App.vue @@ -41,12 +41,18 @@ + @@ -71,6 +77,7 @@ import ToggleComponent from "../TicketList/components/ToggleComponent.vue"; // Translations import { trans, + CHILL_TICKET_TICKET_INIT_FORM_SUBMIT, CHILL_TICKET_TICKET_INIT_FORM_TITLE, CHILL_TICKET_TICKET_INIT_FORM_SUCCESS, CHILL_TICKET_TICKET_INIT_FORM_ERROR, @@ -96,26 +103,39 @@ const showTicketInitFormModal = ref(false); const loading = ref(true); const refreshKey = ref(0); -async function handleFormSubmit(ticketForm: TicketInitForm) { +// ticketForm réactif pour v-model +const ticketForm = ref({ + content: "", + addressees: ticket.value?.currentAddressees, + motive: ticket.value?.currentMotive, + persons: ticket.value?.currentPersons, + caller: ticket.value?.caller, + emergency: ticket.value?.emergency, +} as TicketInitForm); + +async function handleFormSubmit() { try { - if (!ticketForm.motive || ticketForm.content.trim() === "") { + if (!ticketForm.value.motive || ticketForm.value.content.trim() === "") { toast.warning(trans(CHILL_TICKET_TICKET_INIT_FORM_WARNING)); return; } - if (ticketForm.motive) { - await store.dispatch("createMotive", ticketForm.motive); + if (ticketForm.value.motive) { + await store.dispatch("createMotive", ticketForm.value.motive); } - if (ticketForm.content.trim() !== "") { - await store.dispatch("createComment", ticketForm.content); + if (ticketForm.value.content.trim() !== "") { + await store.dispatch("createComment", ticketForm.value.content); } // Ne pas mettre à jour emergency si le motif force l'état d'urgence - if (ticketForm.motive && !ticketForm.motive.makeTicketEmergency) { - await store.dispatch("setEmergency", ticketForm.emergency); + if ( + ticketForm.value.motive && + !ticketForm.value.motive.makeTicketEmergency + ) { + await store.dispatch("setEmergency", ticketForm.value.emergency); } - await store.dispatch("setAddressees", ticketForm.addressees); - await store.dispatch("setPersons", ticketForm.persons); + await store.dispatch("setAddressees", ticketForm.value.addressees); + await store.dispatch("setPersons", ticketForm.value.persons); // Forcer le rafraîchissement des composants refreshKey.value++; diff --git a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketInitFormComponent.vue b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketInitFormComponent.vue index 7a3066251..463209f1a 100644 --- a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketInitFormComponent.vue +++ b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketInitFormComponent.vue @@ -1,84 +1,73 @@ @@ -94,20 +83,12 @@ import PersonsSelectorComponent from "./Person/PersonsSelectorComponent.vue"; import AddresseeSelectorComponent from "./Addressee/AddresseeSelectorComponent.vue"; import EmergencyToggleComponent from "./Emergency/EmergencyToggleComponent.vue"; // Types -import { - Motive, - MotiveWithParent, - Ticket, - TicketEmergencyState, - TicketInitForm, -} from "../../../types"; +import { Motive, TicketInitForm } from "../../../types"; import { Person } from "ChillPersonAssets/types"; // Translations import { trans, - CHILL_TICKET_TICKET_INIT_FORM_SUBMIT, - CHILL_TICKET_TICKET_INIT_FORM_RESET, CHILL_TICKET_TICKET_SET_MOTIVE_TITLE, CHILL_TICKET_TICKET_ADD_COMMENT_TITLE, CHILL_TICKET_TICKET_SET_PERSONS_TITLE_CALLER, @@ -117,32 +98,23 @@ import { CHILL_TICKET_LIST_FILTER_EMERGENCY, CHILL_TICKET_TICKET_ADD_ADDRESSEE_TITLE, } from "translator"; -import { UserGroup, UserGroupOrUser } from "ChillMainAssets/types"; +import { UserGroup } from "ChillMainAssets/types"; const props = defineProps<{ - ticket: Ticket; + modelValue: TicketInitForm; motives: Motive[]; suggestedPersons: Person[]; }>(); const emit = defineEmits<{ "update:modelValue": [value: TicketInitForm]; - submit: [formData: TicketInitForm]; }>(); const store = useStore(); -const ticketForm = reactive({ - content: "", - addressees: props.ticket.currentAddressees as UserGroupOrUser[], - motive: props.ticket.currentMotive as MotiveWithParent | null, - persons: props.ticket.currentPersons as Person[], - caller: props.ticket.caller as Person | null, - emergency: props.ticket.emergency as TicketEmergencyState, -} as TicketInitForm); - +const ticketForm = reactive({ ...props.modelValue }); const isEmergency = ref( - props.ticket.emergency == "yes" ? true : false, + props.modelValue.emergency == "yes" ? true : false, ); const userGroups = computed(() => store.getters.getUserGroups as UserGroup[]); @@ -155,23 +127,16 @@ watch( }, ); -function submitForm() { - emit("submit", { - content: ticketForm.content, - motive: ticketForm.motive, - addressees: [...ticketForm.addressees], - persons: [...ticketForm.persons], - caller: ticketForm.caller, - emergency: isEmergency.value ? "yes" : "no", - }); -} -function resetForm() { - ticketForm.content = ""; - ticketForm.motive = null; - ticketForm.persons = []; - ticketForm.caller = null; - ticketForm.emergency = props.ticket.emergency as TicketEmergencyState; -} +watch( + ticketForm, + (newVal) => { + emit("update:modelValue", { + ...newVal, + emergency: isEmergency.value ? "yes" : "no", + }); + }, + { deep: true }, +);