hazo_collab_forms 5.9.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGE_LOG.md +48 -0
- package/README.md +88 -114
- package/dist/audit/built_in_actions.d.ts +6 -0
- package/dist/audit/built_in_actions.d.ts.map +1 -0
- package/dist/audit/built_in_actions.js +23 -0
- package/dist/audit/built_in_actions.js.map +1 -0
- package/dist/audit/intent_emitter.d.ts +4 -0
- package/dist/audit/intent_emitter.d.ts.map +1 -0
- package/dist/audit/intent_emitter.js +25 -0
- package/dist/audit/intent_emitter.js.map +1 -0
- package/dist/audit/lazy_audit_icon.d.ts +8 -0
- package/dist/audit/lazy_audit_icon.d.ts.map +1 -0
- package/dist/audit/lazy_audit_icon.js +20 -0
- package/dist/audit/lazy_audit_icon.js.map +1 -0
- package/dist/components/_internal_form_set.d.ts +6 -0
- package/dist/components/_internal_form_set.d.ts.map +1 -1
- package/dist/components/_internal_form_set.js +48 -51
- package/dist/components/_internal_form_set.js.map +1 -1
- package/dist/components/clarification/clarification_item_body.d.ts +1 -1
- package/dist/components/clarification/clarification_item_body.d.ts.map +1 -1
- package/dist/components/clarification/resolution_status_strip.d.ts +1 -1
- package/dist/components/clarification/resolution_status_strip.d.ts.map +1 -1
- package/dist/components/field_audit/index.d.ts +5 -0
- package/dist/components/field_audit/index.d.ts.map +1 -1
- package/dist/components/field_audit/index.js +5 -0
- package/dist/components/field_audit/index.js.map +1 -1
- package/dist/components/hazo_collab_form_view/context.d.ts +1 -1
- package/dist/components/hazo_collab_form_view/context.d.ts.map +1 -1
- package/dist/components/hazo_collab_form_view/context.js +10 -2
- package/dist/components/hazo_collab_form_view/context.js.map +1 -1
- package/dist/components/hazo_collab_form_view/hooks/use_view_callbacks.d.ts +8 -1
- package/dist/components/hazo_collab_form_view/hooks/use_view_callbacks.d.ts.map +1 -1
- package/dist/components/hazo_collab_form_view/hooks/use_view_callbacks.js +4 -2
- package/dist/components/hazo_collab_form_view/hooks/use_view_callbacks.js.map +1 -1
- package/dist/components/hazo_collab_form_view/index.d.ts.map +1 -1
- package/dist/components/hazo_collab_form_view/index.js +46 -2
- package/dist/components/hazo_collab_form_view/index.js.map +1 -1
- package/dist/components/hazo_collab_form_view/types.d.ts +36 -0
- package/dist/components/hazo_collab_form_view/types.d.ts.map +1 -1
- package/dist/components/hazo_collab_form_view/views/approval_view.d.ts.map +1 -1
- package/dist/components/hazo_collab_form_view/views/approval_view.js +4 -3
- package/dist/components/hazo_collab_form_view/views/approval_view.js.map +1 -1
- package/dist/components/hazo_collab_form_view/views/edit_view.d.ts.map +1 -1
- package/dist/components/hazo_collab_form_view/views/edit_view.js +8 -3
- package/dist/components/hazo_collab_form_view/views/edit_view.js.map +1 -1
- package/dist/components/hazo_collab_form_view/views/print_view.d.ts.map +1 -1
- package/dist/components/hazo_collab_form_view/views/print_view.js +4 -3
- package/dist/components/hazo_collab_form_view/views/print_view.js.map +1 -1
- package/dist/components/hazo_collab_form_view/views/summary_view.d.ts.map +1 -1
- package/dist/components/hazo_collab_form_view/views/summary_view.js +4 -3
- package/dist/components/hazo_collab_form_view/views/summary_view.js.map +1 -1
- package/dist/components/hazo_data_form/group_renderer.d.ts +4 -2
- package/dist/components/hazo_data_form/group_renderer.d.ts.map +1 -1
- package/dist/components/hazo_data_form/group_renderer.js +3 -3
- package/dist/components/hazo_data_form/group_renderer.js.map +1 -1
- package/dist/components/hazo_data_form/hazo_data_form.d.ts +1 -1
- package/dist/components/hazo_data_form/hazo_data_form.d.ts.map +1 -1
- package/dist/components/hazo_data_form/hazo_data_form.js +36 -4
- package/dist/components/hazo_data_form/hazo_data_form.js.map +1 -1
- package/dist/components/hazo_data_form/section_renderer.d.ts +3 -2
- package/dist/components/hazo_data_form/section_renderer.d.ts.map +1 -1
- package/dist/components/hazo_data_form/section_renderer.js +2 -2
- package/dist/components/hazo_data_form/section_renderer.js.map +1 -1
- package/dist/components/hazo_data_form/shared/data_form_field_layout.d.ts +4 -1
- package/dist/components/hazo_data_form/shared/data_form_field_layout.d.ts.map +1 -1
- package/dist/components/hazo_data_form/shared/data_form_field_layout.js +20 -5
- package/dist/components/hazo_data_form/shared/data_form_field_layout.js.map +1 -1
- package/dist/components/hazo_data_form/types.d.ts +26 -1
- package/dist/components/hazo_data_form/types.d.ts.map +1 -1
- package/dist/components/index.d.ts +0 -4
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +0 -4
- package/dist/components/index.js.map +1 -1
- package/dist/components/shared/base_field_layout.js +1 -1
- package/dist/components/shared/base_field_layout.js.map +1 -1
- package/dist/components/shared/field_action_array_slot.d.ts +10 -0
- package/dist/components/shared/field_action_array_slot.d.ts.map +1 -0
- package/dist/components/shared/field_action_array_slot.js +33 -0
- package/dist/components/shared/field_action_array_slot.js.map +1 -0
- package/dist/components/shared/ihelp_icon.d.ts +1 -1
- package/dist/components/shared/ihelp_icon.js +1 -1
- package/dist/components/shared/rule_result_card.js +1 -1
- package/dist/components/shared/rule_result_card.js.map +1 -1
- package/dist/components/shared/use_field_action_slot.d.ts +8 -3
- package/dist/components/shared/use_field_action_slot.d.ts.map +1 -1
- package/dist/components/shared/use_field_action_slot.js +30 -5
- package/dist/components/shared/use_field_action_slot.js.map +1 -1
- package/dist/components/thread_form/components/send_back_message.d.ts +1 -1
- package/dist/components/thread_form/components/send_back_message.d.ts.map +1 -1
- package/dist/components/thread_form/hooks/use_file_pipeline.d.ts +1 -1
- package/dist/components/thread_form/hooks/use_file_pipeline.d.ts.map +1 -1
- package/dist/components/thread_form/hooks/use_file_pipeline.js +1 -1
- package/dist/components/thread_form/hooks/use_file_pipeline.js.map +1 -1
- package/dist/components/thread_form/thread_form.js +1 -1
- package/dist/components/thread_form/thread_form.js.map +1 -1
- package/dist/components/thread_form/types.d.ts +3 -3
- package/dist/components/thread_form/types.d.ts.map +1 -1
- package/dist/lib/index.d.ts +0 -2
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +0 -2
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/resolution_handler.d.ts +1 -1
- package/dist/lib/resolution_handler.d.ts.map +1 -1
- package/dist/lib/resolve_variable.d.ts +1 -1
- package/dist/lib/resolve_variable.d.ts.map +1 -1
- package/dist/types/clarification.d.ts +1 -1
- package/dist/types/clarification.d.ts.map +1 -1
- package/dist/types/field_action.d.ts +25 -0
- package/dist/types/field_action.d.ts.map +1 -0
- package/dist/types/field_action.js +8 -0
- package/dist/types/field_action.js.map +1 -0
- package/dist/types/index.d.ts +3 -6
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -3
- package/dist/types/index.js.map +1 -1
- package/dist/types/{fb_form_data.d.ts → shared_data.d.ts} +1 -3
- package/dist/types/shared_data.d.ts.map +1 -0
- package/dist/types/{fb_form_data.js → shared_data.js} +1 -2
- package/dist/types/shared_data.js.map +1 -0
- package/dist/utils/dev_file_manager.d.ts +1 -1
- package/dist/utils/dev_file_manager.js +1 -1
- package/dist/{components/hazo_fb_form/shared → utils}/format.d.ts +2 -2
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/{components/hazo_fb_form/shared → utils}/format.js +1 -1
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/index.d.ts +1 -9
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -15
- package/dist/utils/index.js.map +1 -1
- package/package.json +6 -1
- package/dist/components/hazo_fb_form/components/backoffice_run_button.d.ts +0 -18
- package/dist/components/hazo_fb_form/components/backoffice_run_button.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/components/backoffice_run_button.js +0 -23
- package/dist/components/hazo_fb_form/components/backoffice_run_button.js.map +0 -1
- package/dist/components/hazo_fb_form/components/draft_clarification_card.d.ts +0 -39
- package/dist/components/hazo_fb_form/components/draft_clarification_card.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/components/draft_clarification_card.js +0 -94
- package/dist/components/hazo_fb_form/components/draft_clarification_card.js.map +0 -1
- package/dist/components/hazo_fb_form/components/fb_document_type_editor.d.ts +0 -11
- package/dist/components/hazo_fb_form/components/fb_document_type_editor.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/components/fb_document_type_editor.js +0 -82
- package/dist/components/hazo_fb_form/components/fb_document_type_editor.js.map +0 -1
- package/dist/components/hazo_fb_form/components/fb_tag_editor.d.ts +0 -11
- package/dist/components/hazo_fb_form/components/fb_tag_editor.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/components/fb_tag_editor.js +0 -107
- package/dist/components/hazo_fb_form/components/fb_tag_editor.js.map +0 -1
- package/dist/components/hazo_fb_form/components/front_office_stepper.d.ts +0 -15
- package/dist/components/hazo_fb_form/components/front_office_stepper.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/components/front_office_stepper.js +0 -21
- package/dist/components/hazo_fb_form/components/front_office_stepper.js.map +0 -1
- package/dist/components/hazo_fb_form/components/instance_sidebar.d.ts +0 -21
- package/dist/components/hazo_fb_form/components/instance_sidebar.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/components/instance_sidebar.js +0 -58
- package/dist/components/hazo_fb_form/components/instance_sidebar.js.map +0 -1
- package/dist/components/hazo_fb_form/components/reject_clarification_dialog.d.ts +0 -15
- package/dist/components/hazo_fb_form/components/reject_clarification_dialog.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/components/reject_clarification_dialog.js +0 -26
- package/dist/components/hazo_fb_form/components/reject_clarification_dialog.js.map +0 -1
- package/dist/components/hazo_fb_form/components/run_button.d.ts +0 -19
- package/dist/components/hazo_fb_form/components/run_button.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/components/run_button.js +0 -38
- package/dist/components/hazo_fb_form/components/run_button.js.map +0 -1
- package/dist/components/hazo_fb_form/components/run_details_dialog.d.ts +0 -17
- package/dist/components/hazo_fb_form/components/run_details_dialog.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/components/run_details_dialog.js +0 -35
- package/dist/components/hazo_fb_form/components/run_details_dialog.js.map +0 -1
- package/dist/components/hazo_fb_form/components/sent_clarification_group.d.ts +0 -30
- package/dist/components/hazo_fb_form/components/sent_clarification_group.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/components/sent_clarification_group.js +0 -76
- package/dist/components/hazo_fb_form/components/sent_clarification_group.js.map +0 -1
- package/dist/components/hazo_fb_form/components/tag_pill.d.ts +0 -15
- package/dist/components/hazo_fb_form/components/tag_pill.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/components/tag_pill.js +0 -15
- package/dist/components/hazo_fb_form/components/tag_pill.js.map +0 -1
- package/dist/components/hazo_fb_form/context.d.ts +0 -135
- package/dist/components/hazo_fb_form/context.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/context.js +0 -13
- package/dist/components/hazo_fb_form/context.js.map +0 -1
- package/dist/components/hazo_fb_form/hazo_fb_form.d.ts +0 -13
- package/dist/components/hazo_fb_form/hazo_fb_form.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/hazo_fb_form.js +0 -1188
- package/dist/components/hazo_fb_form/hazo_fb_form.js.map +0 -1
- package/dist/components/hazo_fb_form/hooks/use_fb_form_state.d.ts +0 -58
- package/dist/components/hazo_fb_form/hooks/use_fb_form_state.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/hooks/use_fb_form_state.js +0 -919
- package/dist/components/hazo_fb_form/hooks/use_fb_form_state.js.map +0 -1
- package/dist/components/hazo_fb_form/hooks/use_llm_run.d.ts +0 -52
- package/dist/components/hazo_fb_form/hooks/use_llm_run.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/hooks/use_llm_run.js +0 -1863
- package/dist/components/hazo_fb_form/hooks/use_llm_run.js.map +0 -1
- package/dist/components/hazo_fb_form/index.d.ts +0 -29
- package/dist/components/hazo_fb_form/index.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/index.js +0 -19
- package/dist/components/hazo_fb_form/index.js.map +0 -1
- package/dist/components/hazo_fb_form/shared/agent_stepper.d.ts +0 -9
- package/dist/components/hazo_fb_form/shared/agent_stepper.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/shared/agent_stepper.js +0 -17
- package/dist/components/hazo_fb_form/shared/agent_stepper.js.map +0 -1
- package/dist/components/hazo_fb_form/shared/clarification_helpers.d.ts +0 -15
- package/dist/components/hazo_fb_form/shared/clarification_helpers.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/shared/clarification_helpers.js +0 -23
- package/dist/components/hazo_fb_form/shared/clarification_helpers.js.map +0 -1
- package/dist/components/hazo_fb_form/shared/file_status_accordion.d.ts +0 -9
- package/dist/components/hazo_fb_form/shared/file_status_accordion.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/shared/file_status_accordion.js +0 -39
- package/dist/components/hazo_fb_form/shared/file_status_accordion.js.map +0 -1
- package/dist/components/hazo_fb_form/shared/file_utils.d.ts +0 -9
- package/dist/components/hazo_fb_form/shared/file_utils.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/shared/file_utils.js +0 -31
- package/dist/components/hazo_fb_form/shared/file_utils.js.map +0 -1
- package/dist/components/hazo_fb_form/shared/format.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/shared/format.js.map +0 -1
- package/dist/components/hazo_fb_form/shared/group_debug_icon.d.ts +0 -15
- package/dist/components/hazo_fb_form/shared/group_debug_icon.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/shared/group_debug_icon.js +0 -48
- package/dist/components/hazo_fb_form/shared/group_debug_icon.js.map +0 -1
- package/dist/components/hazo_fb_form/shared/index.d.ts +0 -10
- package/dist/components/hazo_fb_form/shared/index.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/shared/index.js +0 -9
- package/dist/components/hazo_fb_form/shared/index.js.map +0 -1
- package/dist/components/hazo_fb_form/shared/pdf_side_panel.d.ts +0 -22
- package/dist/components/hazo_fb_form/shared/pdf_side_panel.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/shared/pdf_side_panel.js +0 -10
- package/dist/components/hazo_fb_form/shared/pdf_side_panel.js.map +0 -1
- package/dist/components/hazo_fb_form/shared/send_back_item_card.d.ts +0 -44
- package/dist/components/hazo_fb_form/shared/send_back_item_card.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/shared/send_back_item_card.js +0 -80
- package/dist/components/hazo_fb_form/shared/send_back_item_card.js.map +0 -1
- package/dist/components/hazo_fb_form/shared/use_pdf_viewer.d.ts +0 -28
- package/dist/components/hazo_fb_form/shared/use_pdf_viewer.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/shared/use_pdf_viewer.js +0 -46
- package/dist/components/hazo_fb_form/shared/use_pdf_viewer.js.map +0 -1
- package/dist/components/hazo_fb_form/types.d.ts +0 -372
- package/dist/components/hazo_fb_form/types.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/types.js +0 -5
- package/dist/components/hazo_fb_form/types.js.map +0 -1
- package/dist/components/hazo_fb_form/views/back_office_view.d.ts +0 -7
- package/dist/components/hazo_fb_form/views/back_office_view.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/views/back_office_view.js +0 -425
- package/dist/components/hazo_fb_form/views/back_office_view.js.map +0 -1
- package/dist/components/hazo_fb_form/views/clarifications_view.d.ts +0 -16
- package/dist/components/hazo_fb_form/views/clarifications_view.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/views/clarifications_view.js +0 -291
- package/dist/components/hazo_fb_form/views/clarifications_view.js.map +0 -1
- package/dist/components/hazo_fb_form/views/client_data_view.d.ts +0 -6
- package/dist/components/hazo_fb_form/views/client_data_view.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/views/client_data_view.js +0 -39
- package/dist/components/hazo_fb_form/views/client_data_view.js.map +0 -1
- package/dist/components/hazo_fb_form/views/front_office_view.d.ts +0 -6
- package/dist/components/hazo_fb_form/views/front_office_view.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/views/front_office_view.js +0 -1351
- package/dist/components/hazo_fb_form/views/front_office_view.js.map +0 -1
- package/dist/components/hazo_fb_form/views/interim_view.d.ts +0 -8
- package/dist/components/hazo_fb_form/views/interim_view.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/views/interim_view.js +0 -535
- package/dist/components/hazo_fb_form/views/interim_view.js.map +0 -1
- package/dist/components/hazo_fb_form/views/review_queue_view.d.ts +0 -14
- package/dist/components/hazo_fb_form/views/review_queue_view.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/views/review_queue_view.js +0 -230
- package/dist/components/hazo_fb_form/views/review_queue_view.js.map +0 -1
- package/dist/components/hazo_fb_form/views/send_back_view.d.ts +0 -13
- package/dist/components/hazo_fb_form/views/send_back_view.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/views/send_back_view.js +0 -258
- package/dist/components/hazo_fb_form/views/send_back_view.js.map +0 -1
- package/dist/components/hazo_fb_form/views/summary_review_view.d.ts +0 -17
- package/dist/components/hazo_fb_form/views/summary_review_view.d.ts.map +0 -1
- package/dist/components/hazo_fb_form/views/summary_review_view.js +0 -258
- package/dist/components/hazo_fb_form/views/summary_review_view.js.map +0 -1
- package/dist/components/shared/json_data_panel/index.d.ts +0 -3
- package/dist/components/shared/json_data_panel/index.d.ts.map +0 -1
- package/dist/components/shared/json_data_panel/index.js +0 -2
- package/dist/components/shared/json_data_panel/index.js.map +0 -1
- package/dist/components/shared/json_data_panel/json_data_panel.d.ts +0 -28
- package/dist/components/shared/json_data_panel/json_data_panel.d.ts.map +0 -1
- package/dist/components/shared/json_data_panel/json_data_panel.js +0 -156
- package/dist/components/shared/json_data_panel/json_data_panel.js.map +0 -1
- package/dist/lib/fb_form_handler.d.ts +0 -63
- package/dist/lib/fb_form_handler.d.ts.map +0 -1
- package/dist/lib/fb_form_handler.js +0 -425
- package/dist/lib/fb_form_handler.js.map +0 -1
- package/dist/types/fb_form_data.d.ts.map +0 -1
- package/dist/types/fb_form_data.js.map +0 -1
- package/dist/types/fb_form_data_v1.d.ts +0 -250
- package/dist/types/fb_form_data_v1.d.ts.map +0 -1
- package/dist/types/fb_form_data_v1.js +0 -117
- package/dist/types/fb_form_data_v1.js.map +0 -1
- package/dist/types/fb_form_instance.d.ts +0 -49
- package/dist/types/fb_form_instance.d.ts.map +0 -1
- package/dist/types/fb_form_instance.js +0 -10
- package/dist/types/fb_form_instance.js.map +0 -1
- package/dist/utils/fb_data_adapter.d.ts +0 -33
- package/dist/utils/fb_data_adapter.d.ts.map +0 -1
- package/dist/utils/fb_data_adapter.js +0 -436
- package/dist/utils/fb_data_adapter.js.map +0 -1
- package/dist/utils/fb_data_adapter_v2.d.ts +0 -17
- package/dist/utils/fb_data_adapter_v2.d.ts.map +0 -1
- package/dist/utils/fb_data_adapter_v2.js +0 -483
- package/dist/utils/fb_data_adapter_v2.js.map +0 -1
- package/dist/utils/fb_data_helpers.d.ts +0 -86
- package/dist/utils/fb_data_helpers.d.ts.map +0 -1
- package/dist/utils/fb_data_helpers.js +0 -269
- package/dist/utils/fb_data_helpers.js.map +0 -1
- package/dist/utils/fb_data_mutations.d.ts +0 -43
- package/dist/utils/fb_data_mutations.d.ts.map +0 -1
- package/dist/utils/fb_data_mutations.js +0 -379
- package/dist/utils/fb_data_mutations.js.map +0 -1
- package/dist/utils/fb_data_mutations_v2.d.ts +0 -46
- package/dist/utils/fb_data_mutations_v2.d.ts.map +0 -1
- package/dist/utils/fb_data_mutations_v2.js +0 -341
- package/dist/utils/fb_data_mutations_v2.js.map +0 -1
- package/dist/utils/fb_data_queries.d.ts +0 -81
- package/dist/utils/fb_data_queries.d.ts.map +0 -1
- package/dist/utils/fb_data_queries.js +0 -354
- package/dist/utils/fb_data_queries.js.map +0 -1
|
@@ -1,919 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Central state management hook for HazoFbForm.
|
|
3
|
-
*/
|
|
4
|
-
'use client';
|
|
5
|
-
import { useState, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
6
|
-
import { use_logger } from '../../../logger/index.js';
|
|
7
|
-
import { VIRTUAL_INSTANCE_ID } from '../hazo_fb_form.js';
|
|
8
|
-
const EMPTY_VALIDATION = {};
|
|
9
|
-
const EMPTY_CLARIFICATIONS = [];
|
|
10
|
-
const EMPTY_REVIEW_DECISIONS = new Map();
|
|
11
|
-
const EMPTY_STRING_SET = new Set();
|
|
12
|
-
const EMPTY_PENDING_RESPONSES = new Map();
|
|
13
|
-
export function use_fb_form_state(props, active_instance_id, active_instance, pending_clarification_responses, form_data_entries) {
|
|
14
|
-
const logger = use_logger();
|
|
15
|
-
const [active_tab, set_active_tab_raw] = useState(props.initial_tab ?? 'front');
|
|
16
|
-
const set_active_tab = useCallback((tab) => {
|
|
17
|
-
logger.debug('[use_fb_form_state] tab_changed', { tab, instance_id: active_instance_id });
|
|
18
|
-
set_active_tab_raw(tab);
|
|
19
|
-
}, [active_instance_id]);
|
|
20
|
-
const [run_progress, set_run_progress] = useState({
|
|
21
|
-
status: 'idle',
|
|
22
|
-
total_steps: 0,
|
|
23
|
-
completed_steps: 0,
|
|
24
|
-
});
|
|
25
|
-
const [classification_results, set_classification_results] = useState(props.classification_results ?? []);
|
|
26
|
-
const [classifying_file_ids, set_classifying_file_ids] = useState(new Set());
|
|
27
|
-
const [unassigned_files, set_unassigned_files] = useState([]);
|
|
28
|
-
const [group_autofill_log, set_group_autofill_log] = useState({});
|
|
29
|
-
const [suggested_document_types, set_suggested_document_types] = useState([]);
|
|
30
|
-
const [queued_file_ids, set_queued_file_ids] = useState(new Set());
|
|
31
|
-
const [manual_review_file_ids, set_manual_review_file_ids] = useState(new Set());
|
|
32
|
-
const [validating_file_ids, set_validating_file_ids] = useState(new Set());
|
|
33
|
-
// ── Per-instance state (keyed by instance_id to avoid stale data on switch) ──
|
|
34
|
-
const instance_key = active_instance_id ?? VIRTUAL_INSTANCE_ID;
|
|
35
|
-
// File validation results — per-instance so auto-populate doesn't leak across instances
|
|
36
|
-
const [validation_map, set_validation_map] = useState(() => {
|
|
37
|
-
// Seed from active instance's persisted validation results
|
|
38
|
-
if (active_instance?.file_validation_results && instance_key) {
|
|
39
|
-
return { [instance_key]: active_instance.file_validation_results };
|
|
40
|
-
}
|
|
41
|
-
return {};
|
|
42
|
-
});
|
|
43
|
-
const file_validation_results = validation_map[instance_key] ?? EMPTY_VALIDATION;
|
|
44
|
-
// Restore persisted file_validation_results when switching to an instance that has them
|
|
45
|
-
useEffect(() => {
|
|
46
|
-
if (active_instance?.file_validation_results && instance_key && !(instance_key in validation_map)) {
|
|
47
|
-
set_validation_map(prev => ({ ...prev, [instance_key]: active_instance.file_validation_results }));
|
|
48
|
-
}
|
|
49
|
-
}, [instance_key]);
|
|
50
|
-
const set_file_validation_results = useCallback((setter) => {
|
|
51
|
-
set_validation_map((prev) => {
|
|
52
|
-
const current = prev[instance_key] ?? {};
|
|
53
|
-
const next = typeof setter === 'function' ? setter(current) : setter;
|
|
54
|
-
return { ...prev, [instance_key]: next };
|
|
55
|
-
});
|
|
56
|
-
}, [instance_key]);
|
|
57
|
-
// Draft clarifications — per-instance so switching doesn't flash stale drafts
|
|
58
|
-
const [drafts_map, set_drafts_map] = useState({});
|
|
59
|
-
const draft_clarifications = drafts_map[instance_key] ?? EMPTY_CLARIFICATIONS;
|
|
60
|
-
const set_draft_clarifications = useCallback((setter) => {
|
|
61
|
-
set_drafts_map((prev) => {
|
|
62
|
-
const current = prev[instance_key] ?? [];
|
|
63
|
-
const next = typeof setter === 'function' ? setter(current) : setter;
|
|
64
|
-
return { ...prev, [instance_key]: next };
|
|
65
|
-
});
|
|
66
|
-
}, [instance_key]);
|
|
67
|
-
// Review decisions — per-instance so switching doesn't mix decisions
|
|
68
|
-
const [review_decisions_map, set_review_decisions_map] = useState({});
|
|
69
|
-
const review_decisions = review_decisions_map[instance_key] ?? EMPTY_REVIEW_DECISIONS;
|
|
70
|
-
const set_review_decisions = useCallback((setter) => {
|
|
71
|
-
set_review_decisions_map((prev) => {
|
|
72
|
-
const current = prev[instance_key] ?? new Map();
|
|
73
|
-
const next = typeof setter === 'function' ? setter(current) : setter;
|
|
74
|
-
return { ...prev, [instance_key]: next };
|
|
75
|
-
});
|
|
76
|
-
}, [instance_key]);
|
|
77
|
-
// Ignored file IDs — per-instance (files where agent chose "dismiss_ignore")
|
|
78
|
-
const [ignored_map, set_ignored_map] = useState({});
|
|
79
|
-
const ignored_file_ids = ignored_map[instance_key] ?? EMPTY_STRING_SET;
|
|
80
|
-
const set_ignored_file_ids = useCallback((setter) => {
|
|
81
|
-
set_ignored_map((prev) => {
|
|
82
|
-
const current = prev[instance_key] ?? new Set();
|
|
83
|
-
const next = typeof setter === 'function' ? setter(current) : setter;
|
|
84
|
-
return { ...prev, [instance_key]: next };
|
|
85
|
-
});
|
|
86
|
-
}, [instance_key]);
|
|
87
|
-
// Skipped file IDs — per-instance (files where agent chose "skip_process")
|
|
88
|
-
const [skipped_map, set_skipped_map] = useState({});
|
|
89
|
-
const skipped_file_ids = skipped_map[instance_key] ?? EMPTY_STRING_SET;
|
|
90
|
-
const set_skipped_file_ids = useCallback((setter) => {
|
|
91
|
-
set_skipped_map((prev) => {
|
|
92
|
-
const current = prev[instance_key] ?? new Set();
|
|
93
|
-
const next = typeof setter === 'function' ? setter(current) : setter;
|
|
94
|
-
return { ...prev, [instance_key]: next };
|
|
95
|
-
});
|
|
96
|
-
}, [instance_key]);
|
|
97
|
-
// Reset per-instance ephemeral state when switching instances
|
|
98
|
-
const prev_instance_id = useRef(active_instance_id);
|
|
99
|
-
useEffect(() => {
|
|
100
|
-
if (active_instance_id !== undefined && active_instance_id !== prev_instance_id.current) {
|
|
101
|
-
logger.info('[use_fb_form_state] instance_switch_reset', { from: prev_instance_id.current, to: active_instance_id });
|
|
102
|
-
prev_instance_id.current = active_instance_id;
|
|
103
|
-
set_active_tab_raw(props.initial_tab ?? 'front');
|
|
104
|
-
set_run_progress({ status: 'idle', total_steps: 0, completed_steps: 0 });
|
|
105
|
-
set_classification_results(props.classification_results ?? []);
|
|
106
|
-
set_classifying_file_ids(new Set());
|
|
107
|
-
set_queued_file_ids(new Set());
|
|
108
|
-
set_unassigned_files([]);
|
|
109
|
-
set_group_autofill_log({});
|
|
110
|
-
set_suggested_document_types([]);
|
|
111
|
-
set_validating_file_ids(new Set());
|
|
112
|
-
// draft_clarifications and file_validation_results are per-instance — no reset needed
|
|
113
|
-
}
|
|
114
|
-
}, [active_instance_id]);
|
|
115
|
-
// Read sent clarifications: per-instance in multi-instance mode, shared in single-instance
|
|
116
|
-
const sent_clarifications = useMemo(() => {
|
|
117
|
-
if (active_instance && active_instance_id && active_instance_id !== VIRTUAL_INSTANCE_ID) {
|
|
118
|
-
return active_instance.sent_clarifications ?? [];
|
|
119
|
-
}
|
|
120
|
-
// Single-instance fallback: read from shared back_form_data
|
|
121
|
-
const raw = props.back_form_data?.['__clarifications'];
|
|
122
|
-
return Array.isArray(raw) ? raw : [];
|
|
123
|
-
}, [active_instance, active_instance_id, props.back_form_data]);
|
|
124
|
-
// Auto-populate drafts from file_validation_results, deduplicating against sent items
|
|
125
|
-
useEffect(() => {
|
|
126
|
-
const all_errors = [];
|
|
127
|
-
for (const result of Object.values(file_validation_results)) {
|
|
128
|
-
if (result.errors && result.errors.length > 0) {
|
|
129
|
-
all_errors.push(...result.errors);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
if (all_errors.length === 0) {
|
|
133
|
-
// Preserve manually-added drafts (e.g., validation_override) even when no validation errors
|
|
134
|
-
set_draft_clarifications((prev) => {
|
|
135
|
-
const manual_only = prev.filter((d) => d.type === 'validation_override');
|
|
136
|
-
if (manual_only.length === prev.length)
|
|
137
|
-
return prev;
|
|
138
|
-
return manual_only;
|
|
139
|
-
});
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
// Build dedup sets from already-sent clarifications
|
|
143
|
-
const sent_ids = new Set(sent_clarifications.map((c) => c.id));
|
|
144
|
-
const sent_keys = new Set(sent_clarifications
|
|
145
|
-
.filter((c) => c.rule_id && c.target_field_id)
|
|
146
|
-
.map((c) => `${c.rule_id}::${c.target_field_id}`));
|
|
147
|
-
// Filter out already-sent items (by id match OR by rule_id::target_field_id match)
|
|
148
|
-
const new_drafts = all_errors.filter((item) => {
|
|
149
|
-
// Direct ID match — this error was already sent
|
|
150
|
-
if (sent_ids.has(item.id))
|
|
151
|
-
return false;
|
|
152
|
-
// Composite key match — same rule + target was already sent (handles re-run with new IDs)
|
|
153
|
-
if (item.rule_id && item.target_field_id && sent_keys.has(`${item.rule_id}::${item.target_field_id}`))
|
|
154
|
-
return false;
|
|
155
|
-
return true;
|
|
156
|
-
});
|
|
157
|
-
// Preserve manually-added drafts (e.g., validation_override) that aren't from validation errors
|
|
158
|
-
set_draft_clarifications((prev) => {
|
|
159
|
-
const manual_drafts = prev.filter((d) => d.type === 'validation_override');
|
|
160
|
-
const merged = [...new_drafts, ...manual_drafts.filter((md) => !new_drafts.some((nd) => nd.id === md.id))];
|
|
161
|
-
const prev_ids = new Set(prev.map((d) => d.id));
|
|
162
|
-
const next_ids = new Set(merged.map((d) => d.id));
|
|
163
|
-
if (prev_ids.size === next_ids.size && [...prev_ids].every((id) => next_ids.has(id)))
|
|
164
|
-
return prev;
|
|
165
|
-
return merged;
|
|
166
|
-
});
|
|
167
|
-
}, [file_validation_results, sent_clarifications, set_draft_clarifications]);
|
|
168
|
-
const update_progress = useCallback((update) => {
|
|
169
|
-
set_run_progress((prev) => ({ ...prev, ...update }));
|
|
170
|
-
}, []);
|
|
171
|
-
const add_classifying_files = useCallback((file_ids) => {
|
|
172
|
-
set_classifying_file_ids((prev) => {
|
|
173
|
-
const next = new Set(prev);
|
|
174
|
-
for (const id of file_ids)
|
|
175
|
-
next.add(id);
|
|
176
|
-
return next;
|
|
177
|
-
});
|
|
178
|
-
}, []);
|
|
179
|
-
const remove_classifying_files = useCallback((file_ids) => {
|
|
180
|
-
set_classifying_file_ids((prev) => {
|
|
181
|
-
const next = new Set(prev);
|
|
182
|
-
for (const id of file_ids)
|
|
183
|
-
next.delete(id);
|
|
184
|
-
return next;
|
|
185
|
-
});
|
|
186
|
-
}, []);
|
|
187
|
-
const add_queued_files = useCallback((file_ids) => {
|
|
188
|
-
set_queued_file_ids((prev) => {
|
|
189
|
-
const next = new Set(prev);
|
|
190
|
-
for (const id of file_ids)
|
|
191
|
-
next.add(id);
|
|
192
|
-
return next;
|
|
193
|
-
});
|
|
194
|
-
}, []);
|
|
195
|
-
const remove_queued_files = useCallback((file_ids) => {
|
|
196
|
-
set_queued_file_ids((prev) => {
|
|
197
|
-
const next = new Set(prev);
|
|
198
|
-
for (const id of file_ids)
|
|
199
|
-
next.delete(id);
|
|
200
|
-
return next;
|
|
201
|
-
});
|
|
202
|
-
}, []);
|
|
203
|
-
// Files currently being autofilled (for spinner display on file chips)
|
|
204
|
-
const [autofilling_file_ids, set_autofilling_file_ids] = useState(new Set());
|
|
205
|
-
// Back-office group collapsed state (persists across tab switches)
|
|
206
|
-
const [back_group_collapsed, set_back_group_collapsed] = useState({});
|
|
207
|
-
// ── Agent stepper state ──
|
|
208
|
-
const [active_step, set_active_step_raw] = useState('review');
|
|
209
|
-
const set_active_step = useCallback((step) => {
|
|
210
|
-
set_active_step_raw(step);
|
|
211
|
-
}, []);
|
|
212
|
-
// ── Per-instance review queue state (keyed by instance_key) ──
|
|
213
|
-
// These MUST be per-instance to prevent Instance 1 decisions leaking into Instance 2.
|
|
214
|
-
// Same pattern as validation_map, drafts_map, review_decisions_map.
|
|
215
|
-
const EMPTY_RQ_DECISIONS = useMemo(() => new Map(), []);
|
|
216
|
-
const EMPTY_SB_COMMENTS = useMemo(() => new Map(), []);
|
|
217
|
-
const [rq_decisions_map, set_rq_decisions_map] = useState({});
|
|
218
|
-
const review_queue_decisions = rq_decisions_map[instance_key] ?? EMPTY_RQ_DECISIONS;
|
|
219
|
-
const set_review_queue_decisions = useCallback((setter) => {
|
|
220
|
-
set_rq_decisions_map((prev) => {
|
|
221
|
-
const current = prev[instance_key] ?? new Map();
|
|
222
|
-
const next = typeof setter === 'function' ? setter(current) : setter;
|
|
223
|
-
return { ...prev, [instance_key]: next };
|
|
224
|
-
});
|
|
225
|
-
}, [instance_key]);
|
|
226
|
-
const [sb_comments_map, set_sb_comments_map] = useState({});
|
|
227
|
-
const send_back_comments = sb_comments_map[instance_key] ?? EMPTY_SB_COMMENTS;
|
|
228
|
-
const set_send_back_comments = useCallback((setter) => {
|
|
229
|
-
set_sb_comments_map((prev) => {
|
|
230
|
-
const current = prev[instance_key] ?? new Map();
|
|
231
|
-
const next = typeof setter === 'function' ? setter(current) : setter;
|
|
232
|
-
return { ...prev, [instance_key]: next };
|
|
233
|
-
});
|
|
234
|
-
}, [instance_key]);
|
|
235
|
-
// Track whether review was completed (persists even when draft_clarifications empty out after processing)
|
|
236
|
-
const [review_was_completed, set_review_was_completed] = useState(false);
|
|
237
|
-
const [confirmed_send_back_count, set_confirmed_send_back_count] = useState(0);
|
|
238
|
-
// Snapshot of review items at time of confirmation (survives draft_clarifications clearing)
|
|
239
|
-
const [confirmed_review_items, set_confirmed_review_items] = useState([]);
|
|
240
|
-
const [confirmed_send_back_items, set_confirmed_send_back_items] = useState([]);
|
|
241
|
-
// Build review queue items from draft clarifications
|
|
242
|
-
const effective_pending = pending_clarification_responses ?? EMPTY_PENDING_RESPONSES;
|
|
243
|
-
const review_queue_items = useMemo(() => {
|
|
244
|
-
// Include responded clarifications from multiple sources:
|
|
245
|
-
// 1. sent_clarifications (standard flow)
|
|
246
|
-
const responded_sent = sent_clarifications.filter(c => c.status === 'responded');
|
|
247
|
-
// 2. front_form_data.__clarifications (sourced items from Instance 2+ that client responded to)
|
|
248
|
-
const front_clrs = Array.isArray(props.front_form_data?.['__clarifications'])
|
|
249
|
-
? props.front_form_data['__clarifications'].filter(c => c.status === 'responded' && c.thread && c.thread.length > 0)
|
|
250
|
-
: [];
|
|
251
|
-
// Combine all sources. When the same clarification exists in both sent_clarifications
|
|
252
|
-
// and front_form_data, use the version with the most complete thread (longest thread).
|
|
253
|
-
// front_form_data.__clarifications may have Instance 2 thread entries that
|
|
254
|
-
// sent_clarifications doesn't have (added by handle_sourced_respond).
|
|
255
|
-
const draft_ids = new Set(draft_clarifications.map(c => c.id));
|
|
256
|
-
const front_clr_map = new Map(front_clrs.map(c => [c.id, c]));
|
|
257
|
-
const all_items = [...draft_clarifications];
|
|
258
|
-
const added_ids = new Set(draft_ids);
|
|
259
|
-
for (const sc of responded_sent) {
|
|
260
|
-
if (added_ids.has(sc.id))
|
|
261
|
-
continue;
|
|
262
|
-
// Prefer the version with the longer thread (more complete conversation)
|
|
263
|
-
const front_version = front_clr_map.get(sc.id);
|
|
264
|
-
if (front_version && (front_version.thread?.length ?? 0) > (sc.thread?.length ?? 0)) {
|
|
265
|
-
all_items.push(front_version);
|
|
266
|
-
}
|
|
267
|
-
else {
|
|
268
|
-
all_items.push(sc);
|
|
269
|
-
}
|
|
270
|
-
added_ids.add(sc.id);
|
|
271
|
-
}
|
|
272
|
-
for (const fc of front_clrs) {
|
|
273
|
-
if (added_ids.has(fc.id))
|
|
274
|
-
continue;
|
|
275
|
-
all_items.push(fc);
|
|
276
|
-
added_ids.add(fc.id);
|
|
277
|
-
}
|
|
278
|
-
return all_items.map((clr) => {
|
|
279
|
-
// Determine category from classification results
|
|
280
|
-
let category = 'uncategorized';
|
|
281
|
-
let category_label = 'Uncategorized';
|
|
282
|
-
const file_id = clr.doc_references?.[0]?.file_id;
|
|
283
|
-
if (file_id) {
|
|
284
|
-
for (const cr of classification_results) {
|
|
285
|
-
const fc = cr.file_classifications?.find((f) => f.file_id === file_id);
|
|
286
|
-
if (fc && fc.tags.length > 0) {
|
|
287
|
-
const tag_id = fc.tags[0];
|
|
288
|
-
const tag = props.available_tags?.find((t) => t.tag_id === tag_id);
|
|
289
|
-
if (tag) {
|
|
290
|
-
category = tag.tag_id;
|
|
291
|
-
category_label = tag.tag_label;
|
|
292
|
-
}
|
|
293
|
-
break;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
// Build client response string from clarification response or validation rule resolution
|
|
298
|
-
let client_response;
|
|
299
|
-
let response_choice = clr.response_choice;
|
|
300
|
-
let user_comment = clr.user_comment;
|
|
301
|
-
// If not on the clarification, check validation rule results and sent_clarifications for user response
|
|
302
|
-
let enriched_status = clr.status;
|
|
303
|
-
if (!response_choice && !user_comment) {
|
|
304
|
-
// Try to find the matching rule result from file_validation_results
|
|
305
|
-
let found_resolution = false;
|
|
306
|
-
// Strategy 1: Look up by file_id + rule_id
|
|
307
|
-
if (file_id && clr.rule_id) {
|
|
308
|
-
const file_result = file_validation_results[file_id];
|
|
309
|
-
const rule_result = file_result?.rule_results?.find(r => r.rule_id === clr.rule_id);
|
|
310
|
-
if (rule_result?.user_resolved && rule_result.user_resolution) {
|
|
311
|
-
response_choice = rule_result.user_resolution.response_choice;
|
|
312
|
-
user_comment = rule_result.user_resolution.user_comment;
|
|
313
|
-
found_resolution = true;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
// Strategy 2: Look up by file_id + rule_name (rule_id might differ)
|
|
317
|
-
if (!found_resolution && file_id && clr.rule_name) {
|
|
318
|
-
const file_result = file_validation_results[file_id];
|
|
319
|
-
const rule_result = file_result?.rule_results?.find(r => r.rule_name === clr.rule_name);
|
|
320
|
-
if (rule_result?.user_resolved && rule_result.user_resolution) {
|
|
321
|
-
response_choice = rule_result.user_resolution.response_choice;
|
|
322
|
-
user_comment = rule_result.user_resolution.user_comment;
|
|
323
|
-
found_resolution = true;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
// Strategy 3: Search all file results for matching rule (file_id on clarification might not match)
|
|
327
|
-
if (!found_resolution && (clr.rule_id || clr.rule_name)) {
|
|
328
|
-
for (const fvr of Object.values(file_validation_results)) {
|
|
329
|
-
const rule_result = fvr.rule_results?.find(r => (clr.rule_id && r.rule_id === clr.rule_id) || (clr.rule_name && r.rule_name === clr.rule_name));
|
|
330
|
-
if (rule_result?.user_resolved && rule_result.user_resolution) {
|
|
331
|
-
response_choice = rule_result.user_resolution.response_choice;
|
|
332
|
-
user_comment = rule_result.user_resolution.user_comment;
|
|
333
|
-
found_resolution = true;
|
|
334
|
-
break;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
// Strategy 4: Check sent_clarifications for matching item with client response
|
|
339
|
-
// (client may have responded to a sent clarification — response lives on instance.sent_clarifications)
|
|
340
|
-
// Match by: ID, rule_id+target, rule_name+target, or same file reference
|
|
341
|
-
if (!found_resolution) {
|
|
342
|
-
const clr_file_id = clr.doc_references?.[0]?.file_id;
|
|
343
|
-
const match = sent_clarifications.find(sc => {
|
|
344
|
-
if (!(sc.response_choice || sc.user_comment))
|
|
345
|
-
return false;
|
|
346
|
-
// Direct ID match
|
|
347
|
-
if (sc.id === clr.id)
|
|
348
|
-
return true;
|
|
349
|
-
// Rule ID + target match
|
|
350
|
-
if (sc.rule_id && sc.rule_id === clr.rule_id && sc.target_field_id === clr.target_field_id)
|
|
351
|
-
return true;
|
|
352
|
-
// Rule name + target match
|
|
353
|
-
if (sc.rule_name && sc.rule_name === clr.rule_name && sc.target_field_id === clr.target_field_id)
|
|
354
|
-
return true;
|
|
355
|
-
// Same rule + same file reference (handles target_field_id differences)
|
|
356
|
-
if (clr_file_id && sc.doc_references?.[0]?.file_id === clr_file_id) {
|
|
357
|
-
if ((sc.rule_id && sc.rule_id === clr.rule_id) || (sc.rule_name && sc.rule_name === clr.rule_name))
|
|
358
|
-
return true;
|
|
359
|
-
}
|
|
360
|
-
return false;
|
|
361
|
-
});
|
|
362
|
-
if (match) {
|
|
363
|
-
response_choice = match.response_choice;
|
|
364
|
-
user_comment = match.user_comment;
|
|
365
|
-
// Also update status to reflect client's response
|
|
366
|
-
if (match.status === 'responded' || match.status === 'resolved') {
|
|
367
|
-
enriched_status = match.status;
|
|
368
|
-
}
|
|
369
|
-
found_resolution = true;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
// Strategy 5: Check pending_clarification_responses (in-memory responses from immediate validation)
|
|
373
|
-
// These are captured when the client selects a response option in the front-office view
|
|
374
|
-
if (!found_resolution) {
|
|
375
|
-
const pending = effective_pending.get(clr.id);
|
|
376
|
-
if (pending?.response_choice || pending?.user_comment) {
|
|
377
|
-
response_choice = pending.response_choice;
|
|
378
|
-
user_comment = pending.user_comment;
|
|
379
|
-
enriched_status = 'responded';
|
|
380
|
-
found_resolution = true;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
if (response_choice || user_comment) {
|
|
385
|
-
const parts = [];
|
|
386
|
-
if (response_choice)
|
|
387
|
-
parts.push(response_choice);
|
|
388
|
-
if (user_comment)
|
|
389
|
-
parts.push(user_comment);
|
|
390
|
-
client_response = parts.join(' — ');
|
|
391
|
-
}
|
|
392
|
-
// Determine source type: text if no doc_references, or if mime_type is text/plain
|
|
393
|
-
const is_text_source = !clr.doc_references?.length
|
|
394
|
-
|| clr.doc_references.every((ref) => ref.mime_type === 'text/plain')
|
|
395
|
-
|| clr.doc_references.some((ref) => ref.file_id?.startsWith('__text_'));
|
|
396
|
-
// Enrich clarification with resolved response data for views to access
|
|
397
|
-
const needs_enrichment = (response_choice || user_comment) && (!clr.response_choice && !clr.user_comment);
|
|
398
|
-
const needs_status_update = enriched_status !== clr.status;
|
|
399
|
-
let enriched_clr = (needs_enrichment || needs_status_update)
|
|
400
|
-
? { ...clr, ...(needs_enrichment ? { response_choice, user_comment } : {}), ...(needs_status_update ? { status: enriched_status } : {}) }
|
|
401
|
-
: clr;
|
|
402
|
-
// Enrich with v2 data model thread — the v2 thread has the complete cross-instance
|
|
403
|
-
// conversation history that the v1 ClarificationItem may be missing.
|
|
404
|
-
if (form_data_entries?.length) {
|
|
405
|
-
for (const entry of form_data_entries) {
|
|
406
|
-
const v2_clr = entry.clarifications?.find((c) => c.clarification_id === clr.id);
|
|
407
|
-
if (v2_clr) {
|
|
408
|
-
// Use v2 thread if it has more entries (includes cross-instance responses)
|
|
409
|
-
if (v2_clr.thread?.length > (enriched_clr.thread?.length ?? 0)) {
|
|
410
|
-
// Collect classification tags from the entry's processed_data for display on file bars
|
|
411
|
-
const entry_tags = [];
|
|
412
|
-
for (const cdi of entry.client_data ?? []) {
|
|
413
|
-
const inp = cdi.client_input;
|
|
414
|
-
for (const pd of inp?.processed_data ?? []) {
|
|
415
|
-
if (pd.tags)
|
|
416
|
-
for (const t of pd.tags)
|
|
417
|
-
if (!entry_tags.includes(t))
|
|
418
|
-
entry_tags.push(t);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
// Collect validations for the info icon
|
|
422
|
-
const entry_validations = entry.validations?.map((v) => ({
|
|
423
|
-
rule_key: v.rule_key ?? '',
|
|
424
|
-
status: v.status ?? '',
|
|
425
|
-
details: v.details ?? '',
|
|
426
|
-
})) ?? [];
|
|
427
|
-
// Convert v2 FbThreadEntry[] to v1 ClarificationThreadEntry[] for the UI
|
|
428
|
-
const v1_thread = v2_clr.thread.map((t) => ({
|
|
429
|
-
role: t.role === 'agent' ? 'author' : t.role,
|
|
430
|
-
action: t.action === 'issue_found' ? 'created' : t.action === 'reviewed' ? (t.decision === 'send_back' ? 'rejected' : 'resolved') : t.action,
|
|
431
|
-
message: t.message || t.comment || t.feedback,
|
|
432
|
-
response_choice: t.choice,
|
|
433
|
-
timestamp: t.time,
|
|
434
|
-
actor_name: t.user_name,
|
|
435
|
-
actor_id: t.user,
|
|
436
|
-
// Attach classification tags and validations to entries with files
|
|
437
|
-
...(t.files?.length ? { classification_tags: entry_tags, validations: entry_validations.length > 0 ? entry_validations : undefined } : {}),
|
|
438
|
-
files: t.files?.map((f) => ({
|
|
439
|
-
file_id: f.file_id,
|
|
440
|
-
ref_id: f.file_id,
|
|
441
|
-
file_name: f.file_name,
|
|
442
|
-
file_size: 0,
|
|
443
|
-
mime_type: 'application/octet-stream',
|
|
444
|
-
visibility: 'public',
|
|
445
|
-
attached_at: t.time,
|
|
446
|
-
})),
|
|
447
|
-
}));
|
|
448
|
-
// Prepend original file/source as the first "Input" entry so the history
|
|
449
|
-
// shows what was submitted before the issue was found.
|
|
450
|
-
// Skip if first entry is already an input (no message, has files).
|
|
451
|
-
const first = v1_thread[0];
|
|
452
|
-
const already_has_input = first && first.role === 'system' && first.action === 'created' && first.files?.length && !first.message;
|
|
453
|
-
if (!already_has_input) {
|
|
454
|
-
const first_thread_time = v2_clr.thread[0]?.time;
|
|
455
|
-
const doc_refs = enriched_clr.doc_references ?? clr.doc_references;
|
|
456
|
-
if (doc_refs?.length > 0) {
|
|
457
|
-
// Deduplicate doc_refs by file_id
|
|
458
|
-
const seen = new Set();
|
|
459
|
-
const unique_refs = doc_refs.filter((ref) => {
|
|
460
|
-
if (seen.has(ref.file_id))
|
|
461
|
-
return false;
|
|
462
|
-
seen.add(ref.file_id);
|
|
463
|
-
return true;
|
|
464
|
-
});
|
|
465
|
-
const input_entry = {
|
|
466
|
-
role: 'system',
|
|
467
|
-
action: 'created',
|
|
468
|
-
files: unique_refs.map((ref) => ({
|
|
469
|
-
file_id: ref.file_id,
|
|
470
|
-
ref_id: ref.file_id,
|
|
471
|
-
file_name: ref.file_name,
|
|
472
|
-
file_size: ref.file_size ?? 0,
|
|
473
|
-
mime_type: ref.mime_type ?? 'application/octet-stream',
|
|
474
|
-
visibility: 'public',
|
|
475
|
-
attached_at: first_thread_time ?? '',
|
|
476
|
-
})),
|
|
477
|
-
timestamp: first_thread_time ?? '',
|
|
478
|
-
validations: entry_validations.length > 0 ? entry_validations : undefined,
|
|
479
|
-
};
|
|
480
|
-
v1_thread.unshift(input_entry);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
enriched_clr = { ...enriched_clr, thread: v1_thread };
|
|
484
|
-
}
|
|
485
|
-
// Use v2 status if more accurate
|
|
486
|
-
if (v2_clr.status === 'responded' && enriched_clr.status !== 'responded') {
|
|
487
|
-
enriched_clr = { ...enriched_clr, status: 'responded' };
|
|
488
|
-
}
|
|
489
|
-
// Clear agent_feedback if v2 review is null (stale feedback from previous round)
|
|
490
|
-
if (v2_clr.review === null && enriched_clr.agent_feedback) {
|
|
491
|
-
enriched_clr = { ...enriched_clr, agent_feedback: undefined };
|
|
492
|
-
}
|
|
493
|
-
break;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
return {
|
|
498
|
-
id: clr.id,
|
|
499
|
-
category,
|
|
500
|
-
category_label,
|
|
501
|
-
source: is_text_source ? 'text' : 'file',
|
|
502
|
-
source_label: clr.doc_references?.[0]?.file_name ?? clr.target_label,
|
|
503
|
-
issue: clr.issue_description,
|
|
504
|
-
client_response,
|
|
505
|
-
clarification: enriched_clr,
|
|
506
|
-
decision: review_queue_decisions.get(clr.id),
|
|
507
|
-
};
|
|
508
|
-
});
|
|
509
|
-
}, [draft_clarifications, classification_results, props.available_tags, review_queue_decisions, file_validation_results, sent_clarifications, effective_pending, props.front_form_data, form_data_entries]);
|
|
510
|
-
// Use live items if available, otherwise fall back to confirmed snapshot
|
|
511
|
-
const effective_review_items = review_queue_items.length > 0 ? review_queue_items : confirmed_review_items;
|
|
512
|
-
// Computed: all items have decisions (or no items exist)
|
|
513
|
-
const review_complete = useMemo(() => {
|
|
514
|
-
if (effective_review_items.length === 0)
|
|
515
|
-
return true;
|
|
516
|
-
return effective_review_items.every((item) => review_queue_decisions.has(item.id));
|
|
517
|
-
}, [effective_review_items, review_queue_decisions]);
|
|
518
|
-
// Computed: items marked as send_back (use snapshot if live items cleared)
|
|
519
|
-
const is_completed_instance = active_instance?.status === 'completed' || active_instance?.status === 'archived';
|
|
520
|
-
const send_back_items = useMemo(() => {
|
|
521
|
-
const live = effective_review_items.filter((item) => review_queue_decisions.get(item.id) === 'send_back');
|
|
522
|
-
if (live.length > 0)
|
|
523
|
-
return live;
|
|
524
|
-
if (confirmed_send_back_items.length > 0)
|
|
525
|
-
return confirmed_send_back_items;
|
|
526
|
-
// For completed instances, rebuild from v2 data model clarifications with sent_back status
|
|
527
|
-
if (is_completed_instance && form_data_entries?.length) {
|
|
528
|
-
const v2_items = [];
|
|
529
|
-
for (const entry of form_data_entries) {
|
|
530
|
-
for (const clr of entry.clarifications ?? []) {
|
|
531
|
-
if (clr.status === 'sent_back' || clr.status === 'accepted') {
|
|
532
|
-
// Find file info from entry's processed_data
|
|
533
|
-
let file_name = '';
|
|
534
|
-
if (entry.client_data) {
|
|
535
|
-
for (const cd of entry.client_data) {
|
|
536
|
-
const inputs = Array.isArray(cd.client_input) ? cd.client_input : [cd.client_input];
|
|
537
|
-
for (const inp of inputs) {
|
|
538
|
-
const pd = inp.processed_data?.find((p) => p.processed_data_id === clr.processed_data_ref);
|
|
539
|
-
if (pd?.processed_data_files?.file_name)
|
|
540
|
-
file_name = pd.processed_data_files.file_name;
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
v2_items.push({
|
|
545
|
-
id: clr.clarification_id,
|
|
546
|
-
category: 'uncategorized',
|
|
547
|
-
category_label: 'Uncategorized',
|
|
548
|
-
source: 'file',
|
|
549
|
-
source_label: file_name || clr.issue,
|
|
550
|
-
issue: clr.issue,
|
|
551
|
-
clarification: { id: clr.clarification_id, issue_description: clr.issue },
|
|
552
|
-
decision: clr.review?.decision ?? 'send_back',
|
|
553
|
-
send_back_comment: clr.review?.feedback,
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
if (v2_items.length > 0)
|
|
559
|
-
return v2_items;
|
|
560
|
-
}
|
|
561
|
-
// Fallback to sent_clarifications (v1 path)
|
|
562
|
-
if (is_completed_instance && sent_clarifications.length > 0) {
|
|
563
|
-
return sent_clarifications.map((clr) => {
|
|
564
|
-
let category = 'uncategorized';
|
|
565
|
-
let category_label = 'Uncategorized';
|
|
566
|
-
const file_id = clr.doc_references?.[0]?.file_id;
|
|
567
|
-
if (file_id) {
|
|
568
|
-
for (const cr of classification_results) {
|
|
569
|
-
const fc = cr.file_classifications?.find(f => f.file_id === file_id);
|
|
570
|
-
if (fc && fc.tags.length > 0) {
|
|
571
|
-
const tag = props.available_tags?.find(t => t.tag_id === fc.tags[0]);
|
|
572
|
-
if (tag) {
|
|
573
|
-
category = tag.tag_id;
|
|
574
|
-
category_label = tag.tag_label;
|
|
575
|
-
}
|
|
576
|
-
break;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
const is_text = !clr.doc_references?.length || clr.doc_references.every(ref => ref.mime_type === 'text/plain');
|
|
581
|
-
return {
|
|
582
|
-
id: clr.id,
|
|
583
|
-
category,
|
|
584
|
-
category_label,
|
|
585
|
-
source: is_text ? 'text' : 'file',
|
|
586
|
-
source_label: clr.doc_references?.[0]?.file_name ?? clr.target_label ?? '',
|
|
587
|
-
issue: clr.issue_description,
|
|
588
|
-
clarification: clr,
|
|
589
|
-
decision: 'send_back',
|
|
590
|
-
};
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
return [];
|
|
594
|
-
}, [effective_review_items, review_queue_decisions, confirmed_send_back_items, is_completed_instance, sent_clarifications, classification_results, props.available_tags, form_data_entries]);
|
|
595
|
-
// Computed: step configurations
|
|
596
|
-
// Steps stay visible once they've been active — even if the underlying data clears after processing
|
|
597
|
-
const step_configs = useMemo(() => {
|
|
598
|
-
const has_review_items = effective_review_items.length > 0;
|
|
599
|
-
const undecided_count = effective_review_items.filter((item) => !review_queue_decisions.has(item.id)).length;
|
|
600
|
-
const labels = props.stepper_labels ?? {};
|
|
601
|
-
// Enable review step if there are items to review, review was completed this session,
|
|
602
|
-
// or there are responded clarifications (client has responded, waiting for agent review)
|
|
603
|
-
const has_responded_clrs = sent_clarifications.some(c => c.status === 'responded')
|
|
604
|
-
|| (form_data_entries ?? []).some((e) => e.clarifications?.some((c) => c.status === 'responded'));
|
|
605
|
-
const review_enabled = has_review_items || review_was_completed || has_responded_clrs;
|
|
606
|
-
const send_back_enabled = send_back_items.length > 0 || confirmed_send_back_count > 0;
|
|
607
|
-
// Check v2 data model for completed send-back state
|
|
608
|
-
const has_v2_sent_back = (form_data_entries ?? []).some((e) => e.clarifications?.some((c) => c.status === 'sent_back' || c.status === 'accepted'));
|
|
609
|
-
return [
|
|
610
|
-
{
|
|
611
|
-
id: 'review',
|
|
612
|
-
label: labels.review ?? 'Review',
|
|
613
|
-
badge_count: undecided_count,
|
|
614
|
-
enabled: review_enabled,
|
|
615
|
-
completed: review_was_completed || (review_complete && has_review_items),
|
|
616
|
-
},
|
|
617
|
-
{
|
|
618
|
-
id: 'tax_data',
|
|
619
|
-
label: labels.tax_data ?? 'Tax Data',
|
|
620
|
-
badge_count: 0,
|
|
621
|
-
enabled: true,
|
|
622
|
-
completed: false,
|
|
623
|
-
},
|
|
624
|
-
{
|
|
625
|
-
id: 'send_back',
|
|
626
|
-
label: labels.send_back ?? 'Send Back',
|
|
627
|
-
badge_count: send_back_items.length || confirmed_send_back_count,
|
|
628
|
-
enabled: send_back_enabled,
|
|
629
|
-
completed: is_completed_instance && (has_v2_sent_back || sent_clarifications.length > 0),
|
|
630
|
-
},
|
|
631
|
-
];
|
|
632
|
-
}, [review_queue_items, review_queue_decisions, review_complete, send_back_items, props.stepper_labels, review_was_completed, confirmed_send_back_count, sent_clarifications, is_completed_instance, form_data_entries]);
|
|
633
|
-
// Confirm review decisions: map to existing review_decisions, collect accepted file IDs, and advance step.
|
|
634
|
-
// Returns accepted file IDs so callers can trigger routing/autofill.
|
|
635
|
-
const confirm_review_decisions = useCallback(() => {
|
|
636
|
-
const sb_count = Array.from(review_queue_decisions.values()).filter(d => d === 'send_back').length;
|
|
637
|
-
set_review_was_completed(true);
|
|
638
|
-
set_confirmed_send_back_count(sb_count);
|
|
639
|
-
// Snapshot items before draft_clarifications get cleared by downstream processing
|
|
640
|
-
// Attach send_back_comment to each item
|
|
641
|
-
const items_with_comments = effective_review_items.map(i => ({
|
|
642
|
-
...i,
|
|
643
|
-
send_back_comment: send_back_comments.get(i.id),
|
|
644
|
-
}));
|
|
645
|
-
set_confirmed_review_items(items_with_comments);
|
|
646
|
-
set_confirmed_send_back_items(items_with_comments.filter(i => review_queue_decisions.get(i.id) === 'send_back'));
|
|
647
|
-
// Collect accepted file IDs for routing — includes original doc_references AND response files
|
|
648
|
-
const accepted_file_ids = [];
|
|
649
|
-
const seen_ids = new Set();
|
|
650
|
-
for (const [item_id, decision] of review_queue_decisions.entries()) {
|
|
651
|
-
if (decision === 'accept') {
|
|
652
|
-
const item = effective_review_items.find(i => i.id === item_id);
|
|
653
|
-
// Original file from doc_references
|
|
654
|
-
const file_id = item?.clarification?.doc_references?.[0]?.file_id;
|
|
655
|
-
if (file_id && !seen_ids.has(file_id)) {
|
|
656
|
-
seen_ids.add(file_id);
|
|
657
|
-
accepted_file_ids.push(file_id);
|
|
658
|
-
}
|
|
659
|
-
// Response files from client (e.g. "provide new and keep existing")
|
|
660
|
-
const response_files = item?.clarification?.response_files;
|
|
661
|
-
if (response_files) {
|
|
662
|
-
for (const rf of response_files) {
|
|
663
|
-
if (rf.file_id && !seen_ids.has(rf.file_id)) {
|
|
664
|
-
seen_ids.add(rf.file_id);
|
|
665
|
-
accepted_file_ids.push(rf.file_id);
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
// Add accepted files to skipped_file_ids (consistent with clarifications_view skip_process flow)
|
|
672
|
-
if (accepted_file_ids.length > 0) {
|
|
673
|
-
set_skipped_file_ids((prev) => {
|
|
674
|
-
const next = new Set(prev);
|
|
675
|
-
for (const id of accepted_file_ids)
|
|
676
|
-
next.add(id);
|
|
677
|
-
return next;
|
|
678
|
-
});
|
|
679
|
-
// Mark all rule_results as accepted so trigger_backoffice_run builds resolved_rules
|
|
680
|
-
// and validate_classified_files skips re-flagging these files
|
|
681
|
-
set_file_validation_results((prev) => {
|
|
682
|
-
const next = { ...prev };
|
|
683
|
-
for (const file_id of accepted_file_ids) {
|
|
684
|
-
const vr = next[file_id];
|
|
685
|
-
if (vr?.rule_results) {
|
|
686
|
-
next[file_id] = {
|
|
687
|
-
...vr,
|
|
688
|
-
rule_results: vr.rule_results.map(rr => ({
|
|
689
|
-
...rr,
|
|
690
|
-
accepted: true,
|
|
691
|
-
})),
|
|
692
|
-
};
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
return next;
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
set_review_decisions((prev) => {
|
|
699
|
-
const next = new Map(prev);
|
|
700
|
-
for (const [item_id, decision] of review_queue_decisions.entries()) {
|
|
701
|
-
if (decision === 'accept') {
|
|
702
|
-
next.set(item_id, 'skip_process');
|
|
703
|
-
}
|
|
704
|
-
else if (decision === 'send_back') {
|
|
705
|
-
next.set(item_id, 'approve');
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
return next;
|
|
709
|
-
});
|
|
710
|
-
set_active_step_raw('tax_data');
|
|
711
|
-
return accepted_file_ids;
|
|
712
|
-
}, [review_queue_decisions, set_review_decisions, effective_review_items, send_back_comments, set_skipped_file_ids, set_file_validation_results]);
|
|
713
|
-
// ── Restore review decisions from v2 data model (single source of truth) ──
|
|
714
|
-
// Per-instance keying ensures clean state per instance — no cross-instance leakage.
|
|
715
|
-
// This effect restores persisted review decisions when an instance's Map is empty.
|
|
716
|
-
const has_restored_decisions = useRef(new Set());
|
|
717
|
-
useEffect(() => {
|
|
718
|
-
if (has_restored_decisions.current.has(instance_key))
|
|
719
|
-
return;
|
|
720
|
-
// With per-instance keying, each instance starts with an empty Map.
|
|
721
|
-
// Only restore if the instance's Map is actually empty.
|
|
722
|
-
if (review_queue_decisions.size > 0) {
|
|
723
|
-
has_restored_decisions.current.add(instance_key);
|
|
724
|
-
return;
|
|
725
|
-
}
|
|
726
|
-
const restored = new Map();
|
|
727
|
-
const restored_comments = new Map();
|
|
728
|
-
// Read from v2 data model
|
|
729
|
-
if (form_data_entries?.length) {
|
|
730
|
-
for (const entry of form_data_entries) {
|
|
731
|
-
for (const clr of entry.clarifications ?? []) {
|
|
732
|
-
if (clr.status === 'responded' || clr.review === null)
|
|
733
|
-
continue;
|
|
734
|
-
if (clr.review?.decision) {
|
|
735
|
-
// Don't restore if a client response came AFTER the review (stale decision)
|
|
736
|
-
const review_thread_ref = clr.review.thread_ref;
|
|
737
|
-
const thread = clr.thread ?? [];
|
|
738
|
-
const review_idx = thread.findIndex((t) => t.thread_id === review_thread_ref);
|
|
739
|
-
const has_newer_client_response = thread.some((t, i) => i > review_idx && t.role === 'client' && t.action === 'responded');
|
|
740
|
-
if (has_newer_client_response)
|
|
741
|
-
continue; // Client responded after review — needs fresh review
|
|
742
|
-
restored.set(clr.clarification_id, clr.review.decision);
|
|
743
|
-
if (clr.review.feedback) {
|
|
744
|
-
restored_comments.set(clr.clarification_id, clr.review.feedback);
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
// Fallback: check v1 sent_clarifications — but ONLY if v2 data isn't available.
|
|
751
|
-
// If v2 data IS available and says review=null, the v1 fallback must respect that.
|
|
752
|
-
// Build a set of clarification IDs where v2 says "needs fresh review" (review=null).
|
|
753
|
-
const v2_needs_fresh_review = new Set();
|
|
754
|
-
if (form_data_entries?.length) {
|
|
755
|
-
for (const entry of form_data_entries) {
|
|
756
|
-
for (const clr of entry.clarifications ?? []) {
|
|
757
|
-
if (clr.review === null || clr.status === 'responded') {
|
|
758
|
-
v2_needs_fresh_review.add(clr.clarification_id);
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
if (restored.size === 0) {
|
|
764
|
-
for (const sc of sent_clarifications) {
|
|
765
|
-
if (sc.status === 'responded')
|
|
766
|
-
continue;
|
|
767
|
-
// If v2 data says this item needs fresh review, don't restore old decisions
|
|
768
|
-
if (v2_needs_fresh_review.has(sc.id))
|
|
769
|
-
continue;
|
|
770
|
-
if (sc.review_decision === 'skip_process') {
|
|
771
|
-
restored.set(sc.id, 'accept');
|
|
772
|
-
}
|
|
773
|
-
else if (sc.review_decision === 'approve') {
|
|
774
|
-
restored.set(sc.id, 'send_back');
|
|
775
|
-
if (sc.agent_feedback)
|
|
776
|
-
restored_comments.set(sc.id, sc.agent_feedback);
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
if (restored.size > 0) {
|
|
781
|
-
has_restored_decisions.current.add(instance_key);
|
|
782
|
-
set_review_queue_decisions(restored);
|
|
783
|
-
set_review_was_completed(true);
|
|
784
|
-
if (restored_comments.size > 0)
|
|
785
|
-
set_send_back_comments(restored_comments);
|
|
786
|
-
logger.info('[use_fb_form_state] restored_review_decisions', {
|
|
787
|
-
instance_key,
|
|
788
|
-
restored_count: restored.size,
|
|
789
|
-
send_back_count: restored_comments.size,
|
|
790
|
-
});
|
|
791
|
-
}
|
|
792
|
-
}, [instance_key, sent_clarifications, form_data_entries, review_queue_decisions.size]);
|
|
793
|
-
// ── Reconcile stale decisions with v2 data model ──
|
|
794
|
-
// The restore effect may run before v2 data is available, restoring stale decisions
|
|
795
|
-
// from v1. This effect runs when v2 data changes and clears any decisions/comments
|
|
796
|
-
// that v2 says should be fresh (review=null, status=responded).
|
|
797
|
-
useEffect(() => {
|
|
798
|
-
if (!form_data_entries?.length)
|
|
799
|
-
return;
|
|
800
|
-
if (review_queue_decisions.size === 0 && send_back_comments.size === 0)
|
|
801
|
-
return;
|
|
802
|
-
const stale_ids = new Set();
|
|
803
|
-
for (const entry of form_data_entries) {
|
|
804
|
-
for (const clr of entry.clarifications ?? []) {
|
|
805
|
-
if (clr.review === null || clr.status === 'responded') {
|
|
806
|
-
if (review_queue_decisions.has(clr.clarification_id) || send_back_comments.has(clr.clarification_id)) {
|
|
807
|
-
stale_ids.add(clr.clarification_id);
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
if (stale_ids.size > 0) {
|
|
813
|
-
set_review_queue_decisions(prev => {
|
|
814
|
-
const next = new Map(prev);
|
|
815
|
-
for (const id of stale_ids)
|
|
816
|
-
next.delete(id);
|
|
817
|
-
return next.size === prev.size ? prev : next;
|
|
818
|
-
});
|
|
819
|
-
set_send_back_comments(prev => {
|
|
820
|
-
const next = new Map(prev);
|
|
821
|
-
for (const id of stale_ids)
|
|
822
|
-
next.delete(id);
|
|
823
|
-
return next.size === prev.size ? prev : next;
|
|
824
|
-
});
|
|
825
|
-
}
|
|
826
|
-
}, [form_data_entries]);
|
|
827
|
-
const stepper_snapshots = useRef({});
|
|
828
|
-
const prev_stepper_instance_id = useRef(active_instance_id);
|
|
829
|
-
useEffect(() => {
|
|
830
|
-
if (!props.agent_stepper)
|
|
831
|
-
return;
|
|
832
|
-
const prev_id = prev_stepper_instance_id.current;
|
|
833
|
-
// Save current stepper state for the previous instance
|
|
834
|
-
if (prev_id && prev_id !== active_instance_id) {
|
|
835
|
-
stepper_snapshots.current[prev_id] = {
|
|
836
|
-
step: active_step,
|
|
837
|
-
was_completed: review_was_completed,
|
|
838
|
-
send_back_count: confirmed_send_back_count,
|
|
839
|
-
review_items: confirmed_review_items,
|
|
840
|
-
send_back_items: confirmed_send_back_items,
|
|
841
|
-
};
|
|
842
|
-
}
|
|
843
|
-
prev_stepper_instance_id.current = active_instance_id;
|
|
844
|
-
// Restore saved state for the new instance, or initialize fresh
|
|
845
|
-
const saved = active_instance_id ? stepper_snapshots.current[active_instance_id] : undefined;
|
|
846
|
-
if (saved) {
|
|
847
|
-
set_active_step_raw(saved.step);
|
|
848
|
-
set_review_was_completed(saved.was_completed);
|
|
849
|
-
set_confirmed_send_back_count(saved.send_back_count);
|
|
850
|
-
set_confirmed_review_items(saved.review_items);
|
|
851
|
-
set_confirmed_send_back_items(saved.send_back_items);
|
|
852
|
-
}
|
|
853
|
-
else if (!has_restored_decisions.current.has(instance_key ?? '')) {
|
|
854
|
-
// Fresh initialization
|
|
855
|
-
if (review_queue_items.length === 0) {
|
|
856
|
-
set_active_step_raw('tax_data');
|
|
857
|
-
}
|
|
858
|
-
else {
|
|
859
|
-
set_active_step_raw('review');
|
|
860
|
-
}
|
|
861
|
-
set_review_was_completed(false);
|
|
862
|
-
set_confirmed_send_back_count(0);
|
|
863
|
-
set_confirmed_review_items([]);
|
|
864
|
-
set_confirmed_send_back_items([]);
|
|
865
|
-
}
|
|
866
|
-
}, [props.agent_stepper, active_instance_id]);
|
|
867
|
-
return {
|
|
868
|
-
active_tab,
|
|
869
|
-
set_active_tab,
|
|
870
|
-
run_progress,
|
|
871
|
-
set_run_progress,
|
|
872
|
-
update_progress,
|
|
873
|
-
classification_results,
|
|
874
|
-
set_classification_results,
|
|
875
|
-
classifying_file_ids,
|
|
876
|
-
add_classifying_files,
|
|
877
|
-
remove_classifying_files,
|
|
878
|
-
queued_file_ids,
|
|
879
|
-
add_queued_files,
|
|
880
|
-
remove_queued_files,
|
|
881
|
-
unassigned_files,
|
|
882
|
-
set_unassigned_files,
|
|
883
|
-
group_autofill_log,
|
|
884
|
-
set_group_autofill_log,
|
|
885
|
-
file_validation_results,
|
|
886
|
-
set_file_validation_results,
|
|
887
|
-
suggested_document_types,
|
|
888
|
-
set_suggested_document_types,
|
|
889
|
-
draft_clarifications,
|
|
890
|
-
set_draft_clarifications,
|
|
891
|
-
sent_clarifications,
|
|
892
|
-
manual_review_file_ids,
|
|
893
|
-
set_manual_review_file_ids,
|
|
894
|
-
validating_file_ids,
|
|
895
|
-
set_validating_file_ids,
|
|
896
|
-
review_decisions,
|
|
897
|
-
set_review_decisions,
|
|
898
|
-
ignored_file_ids,
|
|
899
|
-
set_ignored_file_ids,
|
|
900
|
-
skipped_file_ids,
|
|
901
|
-
set_skipped_file_ids,
|
|
902
|
-
autofilling_file_ids,
|
|
903
|
-
set_autofilling_file_ids,
|
|
904
|
-
back_group_collapsed,
|
|
905
|
-
set_back_group_collapsed,
|
|
906
|
-
active_step,
|
|
907
|
-
set_active_step,
|
|
908
|
-
step_configs,
|
|
909
|
-
review_queue_items: effective_review_items,
|
|
910
|
-
review_queue_decisions,
|
|
911
|
-
set_review_queue_decisions,
|
|
912
|
-
review_complete,
|
|
913
|
-
send_back_items,
|
|
914
|
-
send_back_comments,
|
|
915
|
-
set_send_back_comments,
|
|
916
|
-
confirm_review_decisions,
|
|
917
|
-
};
|
|
918
|
-
}
|
|
919
|
-
//# sourceMappingURL=use_fb_form_state.js.map
|