@@ -34,6 +34,13 @@ class AppActivityLogComponent < ViewComponent::Base
3434 <%= event [ :invalidated ] ? tag . s ( body ) : body %>
3535 </ p > </ blockquote >
3636 <% end %>
37+
38+ <% if ( changes = event [ :changes ] ) . present? %>
39+ <%= render AppDetailsComponent . new ( open : true ) do |details | %>
40+ <% details . with_summary { pluralize ( changes . size , "field" ) + " updated" } %>
41+ <%= changes_summary_list ( changes ) %>
42+ <% end %>
43+ <% end %>
3744 <% end %>
3845 <% end %>
3946 </ div >
@@ -57,6 +64,7 @@ def all_events
5764 gillick_assessment_events ,
5865 note_events ,
5966 notify_events ,
67+ patient_change_events ,
6068 patient_merge_events ,
6169 patient_specific_direction_events ,
6270 pre_screening_events ,
@@ -270,6 +278,26 @@ def notify_events
270278 end
271279 end
272280
281+ CHANGE_SOURCE_TITLES = {
282+ "manual_edit" => "Record updated manually" ,
283+ "cohort_import" =>
284+ "Record updated after new details were imported in a cohort upload" ,
285+ "class_import" =>
286+ "Record updated after new details were imported in a class upload"
287+ } . freeze
288+
289+ def patient_change_events
290+ patient_change_log_entries . map do |entry |
291+ title = CHANGE_SOURCE_TITLES [ entry . source ]
292+ {
293+ title :,
294+ at : entry . created_at ,
295+ by : entry . user ,
296+ changes : entry . recorded_changes
297+ }
298+ end
299+ end
300+
273301 def patient_merge_events
274302 patient_merge_log_entries . map do |patient_merge_log_entry |
275303 {
@@ -435,6 +463,8 @@ def attendance_events
435463
436464 private
437465
466+ delegate :format_nhs_number , :govuk_summary_list , to : :helpers
467+
438468 def include_programme_specific_events?
439469 @programme_type . present? || @session . present?
440470 end
@@ -446,6 +476,13 @@ def archive_reasons
446476 @patient . archive_reasons . where ( team : @team ) . includes ( :created_by )
447477 end
448478
479+ def patient_change_log_entries
480+ return [ ] if include_programme_specific_events?
481+
482+ @patient_change_log_entries ||=
483+ @patient . patient_change_log_entries . includes ( :user )
484+ end
485+
449486 def patient_merge_log_entries
450487 return [ ] if include_programme_specific_events?
451488
@@ -615,6 +652,75 @@ def vaccination_records
615652 end
616653 end
617654
655+ def changes_summary_list ( changes )
656+ rows =
657+ PatientChangeLogEntry ::TRACKED_ATTRIBUTES . filter_map do |attr |
658+ next unless changes . key? ( attr )
659+
660+ old_val , new_val = changes [ attr ]
661+ {
662+ key : {
663+ text : PatientChangeLogEntry . label_for ( attr )
664+ } ,
665+ value : {
666+ text : change_value_html ( attr , old_val , new_val )
667+ }
668+ }
669+ end
670+ govuk_summary_list ( rows :)
671+ end
672+
673+ def change_value_html ( attr , old_val , new_val )
674+ arrow =
675+ tag . svg (
676+ safe_join (
677+ [
678+ tag . title ( "changed to" ) ,
679+ tag . path (
680+ d :
681+ "m14.7 6.3 5 5c.2.2.3.4.3.7 0 .3-.1.5-.3.7l-5 5" \
682+ "a1 1 0 0 1-1.4-1.4l3.3-3.3H5a1 1 0 0 1 0-2" \
683+ "h11.6l-3.3-3.3a1 1 0 1 1 1.4-1.4Z"
684+ )
685+ ]
686+ ) ,
687+ class : "nhsuk-icon nhsuk-icon--arrow-right" ,
688+ style : "vertical-align: middle" ,
689+ xmlns : "http://www.w3.org/2000/svg" ,
690+ viewBox : "0 0 24 24" ,
691+ width : "16" ,
692+ height : "16" ,
693+ focusable : "false" ,
694+ role : "img" ,
695+ "aria-label" : "changed to"
696+ )
697+
698+ safe_join (
699+ [
700+ format_change_value ( attr , old_val ) ,
701+ " " ,
702+ arrow ,
703+ " " ,
704+ tag . mark ( format_change_value ( attr , new_val ) , class : "app-highlight" )
705+ ]
706+ )
707+ end
708+
709+ def format_change_value ( attr , value )
710+ return "Not provided" if value . nil? || value . to_s . empty?
711+
712+ case attr
713+ when "date_of_birth"
714+ Date . parse ( value . to_s ) . to_fs ( :long )
715+ when "gender_code"
716+ Patient . human_enum_name ( :gender_code , value )
717+ when "nhs_number"
718+ format_nhs_number ( value . to_s )
719+ else
720+ value . to_s
721+ end
722+ end
723+
618724 def expired_items_for ( academic_year :, programmes :)
619725 {
620726 consents :,
0 commit comments