Repository: opencrvs/opencrvs-core
Pull request #9535: Display assigned user on event overview summary
Author: login: cibelius
Created: 2025-05-13T07:20:24Z | Merged: 2025-05-14T17:19:36Z

## Description

Resolves https://github.com/opencrvs/opencrvs-core/issues/9501

Display assigned user on event overview summary. Update it when assign/unassign action is executed.

https://github.com/user-attachments/assets/2abb2227-b469-4498-800f-8893f159cd4c


## Checklist

- [x] I have linked the correct Github issue under "Development"
- [x] I have tested the changes locally, and written appropriate tests
- [x] I have tested beyond the happy path (e.g. edge cases, failure paths)
- [ ] I have updated the changelog with this change (if applicable)
- [x] I have updated the GitHub issue status accordingly



Diff:
diff --git a/packages/client/src/v2-events/features/workqueues/EventOverview/EventOverview.tsx b/packages/client/src/v2-events/features/workqueues/EventOverview/EventOverview.tsx
index 0535b7fb290..9d2c9457d0b 100644
--- a/packages/client/src/v2-events/features/workqueues/EventOverview/EventOverview.tsx
+++ b/packages/client/src/v2-events/features/workqueues/EventOverview/EventOverview.tsx
@@ -11,6 +11,7 @@
 import React from 'react'
 import { useTypedParams } from 'react-router-typesafe-routes/dom'
 import { useSelector } from 'react-redux'
+import { useIntl } from 'react-intl'
 import {
   EventDocument,
   getCurrentEventState,
@@ -28,7 +29,8 @@ import { getLocations } from '@client/offline/selectors'
 import { withSuspense } from '@client/v2-events/components/withSuspense'
 import {
   flattenEventIndex,
-  getUserIdsFromActions
+  getUserIdsFromActions,
+  getUsersFullName
 } from '@client/v2-events/utils'
 import { useEventTitle } from '@client/v2-events/features/events/useEvents/useEventTitle'
 import { useDrafts } from '../../drafts/useDrafts'
@@ -36,7 +38,10 @@ import { EventHistory } from './components/EventHistory'
 import { EventSummary } from './components/EventSummary'
 
 import { ActionMenu } from './components/ActionMenu'
-import { EventOverviewProvider } from './EventOverviewContext'
+import {
+  EventOverviewProvider,
+  useEventOverviewContext
+} from './EventOverviewContext'
 
 /**
  * File is based on packages/client/src/views/RecordAudit/RecordAudit.tsx
@@ -45,20 +50,33 @@ import { EventOverviewProvider } from './EventOverviewContext'
 /**
  * Renders the event overview page, including the event summary and history.
  */
-function EventOverview({ event }: { event: EventDocument }) {
+function EventOverview({
+  event,
+  onAction
+}: {
+  event: EventDocument
+  onAction: () => void
+}) {
   const { eventConfiguration } = useEventConfiguration(event.type)
   const eventIndex = getCurrentEventState(event)
   const { trackingId, status, registrationNumber } = eventIndex
   const { getRemoteDrafts } = useDrafts()
   const drafts = getRemoteDrafts()
   const eventWithDrafts = getCurrentEventStateWithDrafts(event, drafts)
+  const { getUser } = useEventOverviewContext()
+  const intl = useIntl()
+
+  const assignedTo = eventIndex.assignedTo
+    ? getUsersFullName(getUser(eventIndex.assignedTo).name, intl.locale)
+    : null
 
   const { flags, ...flattenedEventIndex } = {
     ...flattenEventIndex(eventWithDrafts),
     // @TODO: Ask why these are defined outside of flatten index?
     'event.trackingId': trackingId,
     'event.status': status,
-    'event.registrationNumber': registrationNumber
+    'event.registrationNumber': registrationNumber,
+    'event.assignedTo': assignedTo
   }
 
   const { getEventTitle } = useEventTitle()
@@ -72,7 +90,9 @@ function EventOverview({ event }: { event: EventDocument }) {
       size={ContentSize.LARGE}
       title={title}
       titleColor={event.id ? 'copy' : 'grey600'}
-      topActionButtons={[<ActionMenu key={event.id} eventId={event.id} />]}
+      topActionButtons={[
+        <ActionMenu key={event.id} eventId={event.id} onAction={onAction} />
+      ]}
     >
       <EventSummary
         event={flattenedEventIndex}
@@ -88,7 +108,14 @@ function EventOverviewContainer() {
   const { getEvent } = useEvents()
   const { getUsers } = useUsers()
 
-  const [fullEvent] = getEvent.useSuspenseQuery(params.eventId)
+  // Suspense query is not used here because we want to refetch when an event action is performed
+  const getEventQuery = getEvent.useQuery(params.eventId)
+  const fullEvent = getEventQuery.data
+
+  if (!fullEvent) {
+    return
+  }
+
   const activeActions = getAcceptedActions(fullEvent)
   const userIds = getUserIdsFromActions(activeActions)
   const [users] = getUsers.useSuspenseQuery(userIds)
@@ -96,7 +123,7 @@ function EventOverviewContainer() {
 
   return (
     <EventOverviewProvider locations={locations} users={users}>
-      <EventOverview event={fullEvent} />
+      <EventOverview event={fullEvent} onAction={getEventQuery.refetch} />
     </EventOverviewProvider>
   )
 }
diff --git a/packages/client/src/v2-events/features/workqueues/EventOverview/components/ActionMenu.tsx b/packages/client/src/v2-events/features/workqueues/EventOverview/components/ActionMenu.tsx
index 39d63e5920e..7c07b4ec671 100644
--- a/packages/client/src/v2-events/features/workqueues/EventOverview/components/ActionMenu.tsx
+++ b/packages/client/src/v2-events/features/workqueues/EventOverview/components/ActionMenu.tsx
@@ -22,7 +22,13 @@ import { messages } from '@client/i18n/messages/views/action'
 import { getScope } from '@client/profile/profileSelectors'
 import { useActionMenuItems } from './useActionMenuItems'
 
-export function ActionMenu({ eventId }: { eventId: string }) {
+export function ActionMenu({
+  eventId,
+  onAction
+}: {
+  eventId: string
+  onAction?: () => void
+}) {
   const intl = useIntl()
   const events = useEvents()
   const scopes = useSelector(getScope)
@@ -49,7 +55,10 @@ export function ActionMenu({ eventId }: { eventId: string }) {
               <DropdownMenu.Item
                 key={action.type}
                 disabled={'disabled' in action ? action.disabled : false}
-                onClick={async () => action.onClick(event.id)}
+                onClick={async () => {
+                  await action.onClick(event.id)
+                  onAction?.()
+                }}
               >
                 {intl.formatMessage(action.label)}
               </DropdownMenu.Item>
diff --git a/packages/client/src/v2-events/features/workqueues/EventOverview/components/EventSummary.tsx b/packages/client/src/v2-events/features/workqueues/EventOverview/components/EventSummary.tsx
index 5822a29fbc5..7a8aec4fcdf 100644
--- a/packages/client/src/v2-events/features/workqueues/EventOverview/components/EventSummary.tsx
+++ b/packages/client/src/v2-events/features/workqueues/EventOverview/components/EventSummary.tsx
@@ -31,6 +31,24 @@ function getDefaultFields(
   eventLabel: TranslationConfig
 ): SummaryConfig['fields'] {
   return [
+    {
+      id: 'assignedTo',
+      label: {
+        id: 'v2.event.summary.assignedTo.label',
+        defaultMessage: 'Assigned to',
+        description: 'Assigned to label'
+      },
+      value: {
+        id: 'v2.event.summary.assignedTo.value',
+        defaultMessage: '{event.assignedTo}',
+        description: 'Assigned to value'
+      },
+      emptyValueMessage: {
+        id: 'v2.event.summary.assignedTo.empty',
+        defaultMessage: 'Not assigned',
+        description: 'Not assigned message'
+      }
+    },
     {
       id: 'status',
       label: {
diff --git a/packages/client/src/v2-events/features/workqueues/EventOverview/components/useActionMenuItems.ts b/packages/client/src/v2-events/features/workqueues/EventOverview/components/useActionMenuItems.ts
index c9be6da1be5..4c4d0dec1fe 100644
--- a/packages/client/src/v2-events/features/workqueues/EventOverview/components/useActionMenuItems.ts
+++ b/packages/client/src/v2-events/features/workqueues/EventOverview/components/useActionMenuItems.ts
@@ -196,8 +196,8 @@ export function useActionMenuItems(event: EventIndex, scopes: Scope[]) {
     },
     [ActionType.UNASSIGN]: {
       label: actionLabels[ActionType.UNASSIGN],
-      onClick: (eventId: string) => {
-        events.actions.assignment.unassign.mutate({
+      onClick: async (eventId: string) => {
+        await events.actions.assignment.unassign.mutateAsync({
           eventId,
           transactionId: getUUID(),
           assignedTo: null


Reviews:
user: login: makelicious
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T09:54:37Z

Review comments:
diff_hunk: @@ -88,15 +108,26 @@ function EventOverviewContainer() {
   const { getEvent } = useEvents()
   const { getUsers } = useUsers()
 
-  const [fullEvent] = getEvent.useSuspenseQuery(params.eventId)
+  const getEventQuery = getEvent.useQuery(params.eventId)
path: packages/client/src/v2-events/features/workqueues/EventOverview/EventOverview.tsx
user: login: makelicious
body: Could you add a comment for why suspense is not used (someone like me will revert it by accident)
created_at: 2025-05-13T09:48:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -88,15 +108,26 @@ function EventOverviewContainer() {
   const { getEvent } = useEvents()
   const { getUsers } = useUsers()
 
-  const [fullEvent] = getEvent.useSuspenseQuery(params.eventId)
+  const getEventQuery = getEvent.useQuery(params.eventId)
+  const fullEvent = getEventQuery.data
path: packages/client/src/v2-events/features/workqueues/EventOverview/EventOverview.tsx
user: login: makelicious
body: We already get event from parent, is this different?
created_at: 2025-05-13T09:52:15Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-13T07:20:39Z
body: Oops! Looks like you forgot to update the changelog. When updating CHANGELOG.md, please consider the following:
  - Changelog is read by country implementors who might not always be familiar with all technical details of OpenCRVS. Keep language high-level, user friendly and avoid technical references to internals.
  - Answer "What's new?", "Why was the change made?" and "Why should I care?" for each change.
  - If it's a breaking change, include a migration guide answering "What do I need to do to upgrade?".
author_association: NONE
user: login: ocrvs-bot
created_at: 2025-05-13T07:32:58Z
body: Your environment is deployed to https://ocrvs-9501.opencrvs.dev
author_association: CONTRIBUTOR