From e45af94c78a498cfec099e0e85b175efc02e92a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 3 Jun 2024 23:25:53 +0200 Subject: [PATCH] Update ticket history interface and functionality Reworked the ticket history interface and added new functionalities. The history interface now supports multiple patients and shows changes in patients' state. Additionally, new ticket creation is now displayed in the history line, along with the creator information. Some minor textual changes were made to reflect support for multiple patients. Implemented code cleanup and removed debug statements for a cleaner codebase. --- .../src/Controller/SetPersonsController.php | 2 - .../src/Resources/public/types.ts | 24 +++++-- .../TicketHistoryCreateComponent.vue | 18 ++++++ .../components/TicketHistoryListComponent.vue | 14 ++++- .../TicketHistoryPersonComponent.vue | 52 ++++++---------- .../public/vuejs/TicketApp/i18n/messages.ts | 2 +- .../vuejs/TicketApp/store/modules/ticket.ts | 4 +- .../src/Resources/views/Ticket/list.html.twig | 2 +- .../Normalizer/TicketNormalizer.php | 62 +++++++++++++++++++ 9 files changed, 134 insertions(+), 46 deletions(-) create mode 100644 src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketHistoryCreateComponent.vue diff --git a/src/Bundle/ChillTicketBundle/src/Controller/SetPersonsController.php b/src/Bundle/ChillTicketBundle/src/Controller/SetPersonsController.php index 5289243c2..3fbe254a8 100644 --- a/src/Bundle/ChillTicketBundle/src/Controller/SetPersonsController.php +++ b/src/Bundle/ChillTicketBundle/src/Controller/SetPersonsController.php @@ -44,8 +44,6 @@ final readonly class SetPersonsController $command = $this->serializer->deserialize($request->getContent(), SetPersonsCommand::class, 'json', [AbstractNormalizer::GROUPS => ['read']]); - dump($command); - return $this->registerSetPersons($command, $ticket); } diff --git a/src/Bundle/ChillTicketBundle/src/Resources/public/types.ts b/src/Bundle/ChillTicketBundle/src/Resources/public/types.ts index d4115083e..888d3179e 100644 --- a/src/Bundle/ChillTicketBundle/src/Resources/public/types.ts +++ b/src/Bundle/ChillTicketBundle/src/Resources/public/types.ts @@ -68,14 +68,28 @@ export interface AddresseeState { addressees: UserGroupOrUser[], } -interface AddPersonEvent extends TicketHistory<"add_person", PersonHistory> {}; -interface AddCommentEvent extends TicketHistory<"add_comment", Comment> {}; -interface SetMotiveEvent extends TicketHistory<"set_motive", MotiveHistory> {}; +export interface PersonsState { + persons: Person[] +} + +export interface CreateTicketState {} + +//interface AddPersonEvent extends TicketHistory<"add_person", PersonHistory> {}; +export interface AddCommentEvent extends TicketHistory<"add_comment", Comment> {}; +export interface SetMotiveEvent extends TicketHistory<"set_motive", MotiveHistory> {}; //interface AddAddressee extends TicketHistory<"add_addressee", AddresseeHistory> {}; //interface RemoveAddressee extends TicketHistory<"remove_addressee", AddresseeHistory> {}; -interface AddresseesStateEvent extends TicketHistory<"addressees_state", AddresseeState> {}; +export interface AddresseesStateEvent extends TicketHistory<"addressees_state", AddresseeState> {}; +export interface CreateTicketEvent extends TicketHistory<"create_ticket", CreateTicketState> {}; +export interface PersonStateEvent extends TicketHistory<"persons_state", PersonsState> {}; -export type TicketHistoryLine = AddPersonEvent | AddCommentEvent | SetMotiveEvent | /*AddAddressee | RemoveAddressee | */ AddresseesStateEvent; +export type TicketHistoryLine = + /* AddPersonEvent */ + CreateTicketEvent | + AddCommentEvent | + SetMotiveEvent | /*AddAddressee | RemoveAddressee | */ + AddresseesStateEvent | + PersonStateEvent; export interface Ticket { type: "ticket_ticket", diff --git a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketHistoryCreateComponent.vue b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketHistoryCreateComponent.vue new file mode 100644 index 000000000..869689fdd --- /dev/null +++ b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketHistoryCreateComponent.vue @@ -0,0 +1,18 @@ + + + + + diff --git a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketHistoryListComponent.vue b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketHistoryListComponent.vue index c22b625c9..e60b7b235 100644 --- a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketHistoryListComponent.vue +++ b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketHistoryListComponent.vue @@ -25,7 +25,7 @@
+
@@ -49,13 +53,14 @@ import { useStore } from "vuex"; // Types import { DateTime } from "../../../../../../../ChillMainBundle/Resources/public/types"; -import {Ticket, TicketHistoryLine} from "../../../types"; +import {TicketHistoryLine} from "../../../types"; // Components import TicketHistoryPersonComponent from "./TicketHistoryPersonComponent.vue"; import TicketHistoryMotiveComponent from "./TicketHistoryMotiveComponent.vue"; import TicketHistoryCommentComponent from "./TicketHistoryCommentComponent.vue"; import TicketHistoryAddresseeComponent from "./TicketHistoryAddresseeComponent.vue"; +import TicketHistoryCreateComponent from "./TicketHistoryCreateComponent.vue"; import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue"; import {ISOToDatetime} from "../../../../../../../ChillMainBundle/Resources/public/chill/js/date"; @@ -67,6 +72,7 @@ export default defineComponent({ TicketHistoryMotiveComponent, TicketHistoryCommentComponent, TicketHistoryAddresseeComponent, + TicketHistoryCreateComponent, }, props: { history: { @@ -84,10 +90,12 @@ export default defineComponent({ return "Nouveau commentaire"; case "addressees_state": return "Attributions"; - case "add_person": + case "persons_state": return "Patients concernés"; case "set_motive": return "Nouveau motifs"; + case "create_ticket": + return "Ticket créé"; } }; diff --git a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketHistoryPersonComponent.vue b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketHistoryPersonComponent.vue index 8b4f8a262..f17278a92 100644 --- a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketHistoryPersonComponent.vue +++ b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/components/TicketHistoryPersonComponent.vue @@ -1,57 +1,43 @@ - + diff --git a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/i18n/messages.ts b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/i18n/messages.ts index f16013802..d64434119 100644 --- a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/i18n/messages.ts +++ b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/i18n/messages.ts @@ -38,7 +38,7 @@ const messages = { user_label: "Ajouter un patient", }, banner: { - concerned_patient: "Patient concerné", + concerned_patient: "Patients concernés", speaker: "Attribué à", open: "Ouvert", since: "Depuis {time}", diff --git a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/store/modules/ticket.ts b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/store/modules/ticket.ts index 6be4d6550..cf5c61757 100644 --- a/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/store/modules/ticket.ts +++ b/src/Bundle/ChillTicketBundle/src/Resources/public/vuejs/TicketApp/store/modules/ticket.ts @@ -12,12 +12,14 @@ export const moduleTicket: Module = { state: () => ({ ticket: {} as Ticket, action_icons: { + // TODO cleanup those keys add_person: "fa fa-eyedropper", add_comment: "fa fa-comment", set_motive: "fa fa-paint-brush", //add_addressee: "fa fa-paper-plane", addressees_state: "fa fa-paper-plane", set_persons: "fa fa-eyedropper", + persons_state: "fa fa-eyedropper", }, toto: "toto", }), @@ -37,7 +39,7 @@ export const moduleTicket: Module = { (result, item) => { const { datetime } = item.at; if ( - !["add_addressee", "remove_addressee"].includes( + !["add_addressee", "remove_addressee", "add_person"].includes( item.event_type ) ) { diff --git a/src/Bundle/ChillTicketBundle/src/Resources/views/Ticket/list.html.twig b/src/Bundle/ChillTicketBundle/src/Resources/views/Ticket/list.html.twig index a1bc6b2cb..31465b83d 100644 --- a/src/Bundle/ChillTicketBundle/src/Resources/views/Ticket/list.html.twig +++ b/src/Bundle/ChillTicketBundle/src/Resources/views/Ticket/list.html.twig @@ -46,7 +46,7 @@
{% if ticket.persons|length > 0 %}
-

Patient concerné

+

Patients concernés

{% for p in ticket.persons %} {% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with { diff --git a/src/Bundle/ChillTicketBundle/src/Serializer/Normalizer/TicketNormalizer.php b/src/Bundle/ChillTicketBundle/src/Serializer/Normalizer/TicketNormalizer.php index 8cdaf9988..2b255f207 100644 --- a/src/Bundle/ChillTicketBundle/src/Serializer/Normalizer/TicketNormalizer.php +++ b/src/Bundle/ChillTicketBundle/src/Serializer/Normalizer/TicketNormalizer.php @@ -13,6 +13,7 @@ namespace Chill\TicketBundle\Serializer\Normalizer; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\UserGroup; +use Chill\PersonBundle\Entity\Person; use Chill\TicketBundle\Entity\AddresseeHistory; use Chill\TicketBundle\Entity\Comment; use Chill\TicketBundle\Entity\MotiveHistory; @@ -107,8 +108,19 @@ final class TicketNormalizer implements NormalizerInterface, NormalizerAwareInte ), */ ...$this->addresseesStates($ticket), + ...$this->personStates($ticket), ]; + if (null !== $ticket->getCreatedBy() && null !== $ticket->getCreatedAt()) { + $events[] = + [ + 'event_type' => 'create_ticket', + 'at' => $ticket->getCreatedAt()->sub(new \DateInterval('PT1S')), // TODO hack to avoid collision with creation of the ticket event, + 'by' => $ticket->getCreatedBy(), + 'data' => [], + ]; + } + usort( $events, static function (array $a, array $b): int { @@ -176,4 +188,54 @@ final class TicketNormalizer implements NormalizerInterface, NormalizerAwareInte return $steps; } + + private function personStates(Ticket $ticket): array + { + /** @var array{string, array{added: list, removed: list}} $changes */ + $changes = []; + $dateFormat = 'Y-m-d-m-Y-H-i-s'; + + foreach ($ticket->getPersonHistories() as $history) { + $changes[$history->getStartDate()->format($dateFormat)]['added'][] = $history; + if (null !== $history->getEndDate()) { + $changes[$history->getEndDate()->format($dateFormat)]['removed'][] = $history; + } + } + + ksort($changes); + + $currents = []; + $steps = []; + foreach ($changes as $change) { + $historiesAdded = $change['added'] ?? []; + $historiesRemoved = $change['removed'] ?? []; + + if (0 < count($historiesAdded)) { + $at = $historiesAdded[0]->getStartDate(); + $by = $historiesAdded[0]->getCreatedBy(); + } elseif (0 < count($historiesRemoved)) { + $at = $historiesRemoved[0]->getEndDate(); + $by = $historiesRemoved[0]->getRemovedBy(); + } else { + throw new \LogicException('it should have at least one history'); + } + + $removed = array_map(fn (PersonHistory $history) => $history->getPerson(), $historiesRemoved); + $currents = array_filter($currents, fn (Person $a) => !in_array($a, $removed, true)); + foreach ($historiesAdded as $history) { + $currents[] = $history->getPerson(); + } + + $steps[] = [ + 'event_type' => 'persons_state', + 'at' => $at, + 'by' => $by, + 'data' => [ + 'persons' => array_values($currents), + ], + ]; + } + + return $steps; + } }