hazo_collab_forms 3.1.6 → 5.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 +207 -0
- package/README.md +3 -0
- package/dist/components/clarification/clarification_item_body.d.ts +19 -1
- package/dist/components/clarification/clarification_item_body.d.ts.map +1 -1
- package/dist/components/clarification/clarification_item_body.js +114 -6
- package/dist/components/clarification/clarification_item_body.js.map +1 -1
- package/dist/components/clarification/clarification_thread.js +1 -1
- package/dist/components/clarification/clarification_thread.js.map +1 -1
- package/dist/components/clarification/index.d.ts +2 -0
- package/dist/components/clarification/index.d.ts.map +1 -1
- package/dist/components/clarification/index.js +1 -0
- package/dist/components/clarification/index.js.map +1 -1
- package/dist/components/clarification/resolution_status_strip.d.ts +18 -0
- package/dist/components/clarification/resolution_status_strip.d.ts.map +1 -0
- package/dist/components/clarification/resolution_status_strip.js +20 -0
- package/dist/components/clarification/resolution_status_strip.js.map +1 -0
- package/dist/components/hazo_fb_form/context.d.ts +1 -1
- package/dist/components/hazo_fb_form/context.d.ts.map +1 -1
- package/dist/components/hazo_fb_form/hazo_fb_form.d.ts.map +1 -1
- package/dist/components/hazo_fb_form/hazo_fb_form.js +330 -113
- package/dist/components/hazo_fb_form/hazo_fb_form.js.map +1 -1
- package/dist/components/hazo_fb_form/hooks/use_fb_form_state.d.ts +3 -3
- package/dist/components/hazo_fb_form/hooks/use_fb_form_state.d.ts.map +1 -1
- package/dist/components/hazo_fb_form/hooks/use_fb_form_state.js +340 -61
- package/dist/components/hazo_fb_form/hooks/use_fb_form_state.js.map +1 -1
- package/dist/components/hazo_fb_form/hooks/use_llm_run.d.ts +3 -1
- package/dist/components/hazo_fb_form/hooks/use_llm_run.d.ts.map +1 -1
- package/dist/components/hazo_fb_form/hooks/use_llm_run.js +89 -11
- package/dist/components/hazo_fb_form/hooks/use_llm_run.js.map +1 -1
- package/dist/components/hazo_fb_form/shared/agent_stepper.js +1 -1
- package/dist/components/hazo_fb_form/shared/agent_stepper.js.map +1 -1
- package/dist/components/hazo_fb_form/shared/file_status_accordion.d.ts +9 -0
- package/dist/components/hazo_fb_form/shared/file_status_accordion.d.ts.map +1 -0
- package/dist/components/hazo_fb_form/shared/file_status_accordion.js +39 -0
- package/dist/components/hazo_fb_form/shared/file_status_accordion.js.map +1 -0
- package/dist/components/hazo_fb_form/shared/format.d.ts.map +1 -1
- package/dist/components/hazo_fb_form/shared/format.js +8 -3
- package/dist/components/hazo_fb_form/shared/format.js.map +1 -1
- package/dist/components/hazo_fb_form/shared/send_back_item_card.d.ts +7 -1
- package/dist/components/hazo_fb_form/shared/send_back_item_card.d.ts.map +1 -1
- package/dist/components/hazo_fb_form/shared/send_back_item_card.js +6 -3
- package/dist/components/hazo_fb_form/shared/send_back_item_card.js.map +1 -1
- package/dist/components/hazo_fb_form/types.d.ts +3 -1
- package/dist/components/hazo_fb_form/types.d.ts.map +1 -1
- package/dist/components/hazo_fb_form/views/back_office_view.js +1 -1
- package/dist/components/hazo_fb_form/views/back_office_view.js.map +1 -1
- package/dist/components/hazo_fb_form/views/clarifications_view.js +2 -2
- package/dist/components/hazo_fb_form/views/clarifications_view.js.map +1 -1
- package/dist/components/hazo_fb_form/views/front_office_view.d.ts.map +1 -1
- package/dist/components/hazo_fb_form/views/front_office_view.js +62 -41
- package/dist/components/hazo_fb_form/views/front_office_view.js.map +1 -1
- package/dist/components/hazo_fb_form/views/interim_view.js +3 -3
- package/dist/components/hazo_fb_form/views/interim_view.js.map +1 -1
- package/dist/components/hazo_fb_form/views/review_queue_view.d.ts.map +1 -1
- package/dist/components/hazo_fb_form/views/review_queue_view.js +22 -9
- package/dist/components/hazo_fb_form/views/review_queue_view.js.map +1 -1
- package/dist/components/hazo_validation_rule_editor/components/rule_editor.d.ts.map +1 -1
- package/dist/components/hazo_validation_rule_editor/components/rule_editor.js +32 -3
- package/dist/components/hazo_validation_rule_editor/components/rule_editor.js.map +1 -1
- package/dist/components/hazo_validation_rule_editor/components/variable_chain_input.d.ts +20 -0
- package/dist/components/hazo_validation_rule_editor/components/variable_chain_input.d.ts.map +1 -0
- package/dist/components/hazo_validation_rule_editor/components/variable_chain_input.js +34 -0
- package/dist/components/hazo_validation_rule_editor/components/variable_chain_input.js.map +1 -0
- package/dist/components/hazo_validation_rule_editor/context.d.ts +3 -2
- package/dist/components/hazo_validation_rule_editor/context.d.ts.map +1 -1
- package/dist/components/hazo_validation_rule_editor/context.js +15 -3
- package/dist/components/hazo_validation_rule_editor/context.js.map +1 -1
- package/dist/components/hazo_validation_rule_editor/types.d.ts +7 -1
- package/dist/components/hazo_validation_rule_editor/types.d.ts.map +1 -1
- package/dist/components/hazo_validation_rule_editor/validation_rule_editor.d.ts +1 -1
- package/dist/components/hazo_validation_rule_editor/validation_rule_editor.d.ts.map +1 -1
- package/dist/components/hazo_validation_rule_editor/validation_rule_editor.js +2 -2
- package/dist/components/hazo_validation_rule_editor/validation_rule_editor.js.map +1 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/shared/document_type_editor.d.ts +31 -0
- package/dist/components/shared/document_type_editor.d.ts.map +1 -0
- package/dist/components/shared/document_type_editor.js +60 -0
- package/dist/components/shared/document_type_editor.js.map +1 -0
- package/dist/components/shared/file_bar/file_bar.d.ts +7 -1
- package/dist/components/shared/file_bar/file_bar.d.ts.map +1 -1
- package/dist/components/shared/file_bar/file_bar.js +5 -3
- package/dist/components/shared/file_bar/file_bar.js.map +1 -1
- package/dist/components/shared/file_bar/file_bar_validation_dialog.js +4 -4
- package/dist/components/shared/file_bar/file_bar_validation_dialog.js.map +1 -1
- package/dist/components/shared/file_status_icon.d.ts +23 -0
- package/dist/components/shared/file_status_icon.d.ts.map +1 -0
- package/dist/components/shared/file_status_icon.js +38 -0
- package/dist/components/shared/file_status_icon.js.map +1 -0
- package/dist/components/shared/json_data_panel/json_data_panel.d.ts +1 -1
- package/dist/components/shared/json_data_panel/json_data_panel.d.ts.map +1 -1
- package/dist/components/shared/json_data_panel/json_data_panel.js +27 -2
- package/dist/components/shared/json_data_panel/json_data_panel.js.map +1 -1
- package/dist/components/shared/rule_result_card.d.ts.map +1 -1
- package/dist/components/shared/rule_result_card.js +5 -4
- package/dist/components/shared/rule_result_card.js.map +1 -1
- package/dist/components/thread_form/components/add_question_dialog.d.ts +12 -0
- package/dist/components/thread_form/components/add_question_dialog.d.ts.map +1 -0
- package/dist/components/thread_form/components/add_question_dialog.js +36 -0
- package/dist/components/thread_form/components/add_question_dialog.js.map +1 -0
- package/dist/components/thread_form/components/agent_compose_dialog.d.ts +30 -0
- package/dist/components/thread_form/components/agent_compose_dialog.d.ts.map +1 -0
- package/dist/components/thread_form/components/agent_compose_dialog.js +45 -0
- package/dist/components/thread_form/components/agent_compose_dialog.js.map +1 -0
- package/dist/components/thread_form/components/clarification.d.ts +14 -0
- package/dist/components/thread_form/components/clarification.d.ts.map +1 -0
- package/dist/components/thread_form/components/clarification.js +12 -0
- package/dist/components/thread_form/components/clarification.js.map +1 -0
- package/dist/components/thread_form/components/collected_data_view.d.ts +15 -0
- package/dist/components/thread_form/components/collected_data_view.d.ts.map +1 -0
- package/dist/components/thread_form/components/collected_data_view.js +121 -0
- package/dist/components/thread_form/components/collected_data_view.js.map +1 -0
- package/dist/components/thread_form/components/coverage_card.d.ts +11 -0
- package/dist/components/thread_form/components/coverage_card.d.ts.map +1 -0
- package/dist/components/thread_form/components/coverage_card.js +60 -0
- package/dist/components/thread_form/components/coverage_card.js.map +1 -0
- package/dist/components/thread_form/components/file_bar.d.ts +93 -0
- package/dist/components/thread_form/components/file_bar.d.ts.map +1 -0
- package/dist/components/thread_form/components/file_bar.js +251 -0
- package/dist/components/thread_form/components/file_bar.js.map +1 -0
- package/dist/components/thread_form/components/file_info_dialog.d.ts +15 -0
- package/dist/components/thread_form/components/file_info_dialog.d.ts.map +1 -0
- package/dist/components/thread_form/components/file_info_dialog.js +64 -0
- package/dist/components/thread_form/components/file_info_dialog.js.map +1 -0
- package/dist/components/thread_form/components/issue_group_tree.d.ts +20 -0
- package/dist/components/thread_form/components/issue_group_tree.d.ts.map +1 -0
- package/dist/components/thread_form/components/issue_group_tree.js +164 -0
- package/dist/components/thread_form/components/issue_group_tree.js.map +1 -0
- package/dist/components/thread_form/components/pdf_side_panel.d.ts +20 -0
- package/dist/components/thread_form/components/pdf_side_panel.d.ts.map +1 -0
- package/dist/components/thread_form/components/pdf_side_panel.js +63 -0
- package/dist/components/thread_form/components/pdf_side_panel.js.map +1 -0
- package/dist/components/thread_form/components/rule_decision_row.d.ts +31 -0
- package/dist/components/thread_form/components/rule_decision_row.d.ts.map +1 -0
- package/dist/components/thread_form/components/rule_decision_row.js +20 -0
- package/dist/components/thread_form/components/rule_decision_row.js.map +1 -0
- package/dist/components/thread_form/components/send_back_message.d.ts +32 -0
- package/dist/components/thread_form/components/send_back_message.d.ts.map +1 -0
- package/dist/components/thread_form/components/send_back_message.js +82 -0
- package/dist/components/thread_form/components/send_back_message.js.map +1 -0
- package/dist/components/thread_form/components/shared.d.ts +54 -0
- package/dist/components/thread_form/components/shared.d.ts.map +1 -0
- package/dist/components/thread_form/components/shared.js +136 -0
- package/dist/components/thread_form/components/shared.js.map +1 -0
- package/dist/components/thread_form/components/task_card.d.ts +90 -0
- package/dist/components/thread_form/components/task_card.d.ts.map +1 -0
- package/dist/components/thread_form/components/task_card.js +63 -0
- package/dist/components/thread_form/components/task_card.js.map +1 -0
- package/dist/components/thread_form/components/text_doc_check.d.ts +15 -0
- package/dist/components/thread_form/components/text_doc_check.d.ts.map +1 -0
- package/dist/components/thread_form/components/text_doc_check.js +16 -0
- package/dist/components/thread_form/components/text_doc_check.js.map +1 -0
- package/dist/components/thread_form/components/text_extraction.d.ts +14 -0
- package/dist/components/thread_form/components/text_extraction.d.ts.map +1 -0
- package/dist/components/thread_form/components/text_extraction.js +16 -0
- package/dist/components/thread_form/components/text_extraction.js.map +1 -0
- package/dist/components/thread_form/components/thread_composer.d.ts +15 -0
- package/dist/components/thread_form/components/thread_composer.d.ts.map +1 -0
- package/dist/components/thread_form/components/thread_composer.js +93 -0
- package/dist/components/thread_form/components/thread_composer.js.map +1 -0
- package/dist/components/thread_form/components/thread_timeline.d.ts +65 -0
- package/dist/components/thread_form/components/thread_timeline.d.ts.map +1 -0
- package/dist/components/thread_form/components/thread_timeline.js +225 -0
- package/dist/components/thread_form/components/thread_timeline.js.map +1 -0
- package/dist/components/thread_form/hooks/use_file_pipeline.d.ts +126 -0
- package/dist/components/thread_form/hooks/use_file_pipeline.d.ts.map +1 -0
- package/dist/components/thread_form/hooks/use_file_pipeline.js +760 -0
- package/dist/components/thread_form/hooks/use_file_pipeline.js.map +1 -0
- package/dist/components/thread_form/hooks/use_thread_form.d.ts +36 -0
- package/dist/components/thread_form/hooks/use_thread_form.d.ts.map +1 -0
- package/dist/components/thread_form/hooks/use_thread_form.js +126 -0
- package/dist/components/thread_form/hooks/use_thread_form.js.map +1 -0
- package/dist/components/thread_form/index.d.ts +33 -0
- package/dist/components/thread_form/index.d.ts.map +1 -0
- package/dist/components/thread_form/index.js +30 -0
- package/dist/components/thread_form/index.js.map +1 -0
- package/dist/components/thread_form/sample_data.d.ts +8 -0
- package/dist/components/thread_form/sample_data.d.ts.map +1 -0
- package/dist/components/thread_form/sample_data.js +658 -0
- package/dist/components/thread_form/sample_data.js.map +1 -0
- package/dist/components/thread_form/thread_form.d.ts +7 -0
- package/dist/components/thread_form/thread_form.d.ts.map +1 -0
- package/dist/components/thread_form/thread_form.js +1385 -0
- package/dist/components/thread_form/thread_form.js.map +1 -0
- package/dist/components/thread_form/types.d.ts +402 -0
- package/dist/components/thread_form/types.d.ts.map +1 -0
- package/dist/components/thread_form/types.js +23 -0
- package/dist/components/thread_form/types.js.map +1 -0
- package/dist/components/thread_form/utils/file_decision_state.d.ts +22 -0
- package/dist/components/thread_form/utils/file_decision_state.d.ts.map +1 -0
- package/dist/components/thread_form/utils/file_decision_state.js +37 -0
- package/dist/components/thread_form/utils/file_decision_state.js.map +1 -0
- package/dist/components/thread_form/utils/merge_send_back.d.ts +13 -0
- package/dist/components/thread_form/utils/merge_send_back.d.ts.map +1 -0
- package/dist/components/thread_form/utils/merge_send_back.js +23 -0
- package/dist/components/thread_form/utils/merge_send_back.js.map +1 -0
- package/dist/lib/autofill_handler.d.ts.map +1 -1
- package/dist/lib/autofill_handler.js +5 -44
- package/dist/lib/autofill_handler.js.map +1 -1
- package/dist/lib/classification_handler.d.ts +105 -0
- package/dist/lib/classification_handler.d.ts.map +1 -0
- package/dist/lib/classification_handler.js +342 -0
- package/dist/lib/classification_handler.js.map +1 -0
- package/dist/lib/content_gate_handler.d.ts +37 -0
- package/dist/lib/content_gate_handler.d.ts.map +1 -0
- package/dist/lib/content_gate_handler.js +126 -0
- package/dist/lib/content_gate_handler.js.map +1 -0
- package/dist/lib/index.d.ts +10 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +5 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/periodic_coverage_runner.d.ts +24 -0
- package/dist/lib/periodic_coverage_runner.d.ts.map +1 -0
- package/dist/lib/periodic_coverage_runner.js +121 -0
- package/dist/lib/periodic_coverage_runner.js.map +1 -0
- package/dist/lib/resolution_handler.d.ts +150 -0
- package/dist/lib/resolution_handler.d.ts.map +1 -0
- package/dist/lib/resolution_handler.js +597 -0
- package/dist/lib/resolution_handler.js.map +1 -0
- package/dist/lib/resolve_variable.d.ts +25 -0
- package/dist/lib/resolve_variable.d.ts.map +1 -0
- package/dist/lib/resolve_variable.js +77 -0
- package/dist/lib/resolve_variable.js.map +1 -0
- package/dist/lib/validation_handler.d.ts +27 -3
- package/dist/lib/validation_handler.d.ts.map +1 -1
- package/dist/lib/validation_handler.js +338 -288
- package/dist/lib/validation_handler.js.map +1 -1
- package/dist/types/clarification.d.ts +54 -0
- package/dist/types/clarification.d.ts.map +1 -1
- package/dist/types/fb_form_data.d.ts +273 -123
- package/dist/types/fb_form_data.d.ts.map +1 -1
- package/dist/types/fb_form_data.js +44 -58
- package/dist/types/fb_form_data.js.map +1 -1
- package/dist/types/fb_form_data_v1.d.ts +250 -0
- package/dist/types/fb_form_data_v1.d.ts.map +1 -0
- package/dist/types/fb_form_data_v1.js +117 -0
- package/dist/types/fb_form_data_v1.js.map +1 -0
- package/dist/types/fb_form_instance.d.ts +1 -1
- package/dist/types/fb_form_instance.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/validation.d.ts +134 -12
- package/dist/types/validation.d.ts.map +1 -1
- package/dist/utils/expectation_extractor.d.ts +31 -0
- package/dist/utils/expectation_extractor.d.ts.map +1 -0
- package/dist/utils/expectation_extractor.js +142 -0
- package/dist/utils/expectation_extractor.js.map +1 -0
- package/dist/utils/fb_data_adapter.d.ts +7 -2
- package/dist/utils/fb_data_adapter.d.ts.map +1 -1
- package/dist/utils/fb_data_adapter.js +58 -7
- package/dist/utils/fb_data_adapter.js.map +1 -1
- package/dist/utils/fb_data_adapter_v2.d.ts +17 -0
- package/dist/utils/fb_data_adapter_v2.d.ts.map +1 -0
- package/dist/utils/fb_data_adapter_v2.js +483 -0
- package/dist/utils/fb_data_adapter_v2.js.map +1 -0
- package/dist/utils/fb_data_helpers.d.ts +1 -1
- package/dist/utils/fb_data_helpers.d.ts.map +1 -1
- package/dist/utils/fb_data_mutations.d.ts +1 -1
- package/dist/utils/fb_data_mutations.d.ts.map +1 -1
- package/dist/utils/fb_data_mutations_v2.d.ts +46 -0
- package/dist/utils/fb_data_mutations_v2.d.ts.map +1 -0
- package/dist/utils/fb_data_mutations_v2.js +341 -0
- package/dist/utils/fb_data_mutations_v2.js.map +1 -0
- package/dist/utils/fb_data_queries.d.ts +81 -0
- package/dist/utils/fb_data_queries.d.ts.map +1 -0
- package/dist/utils/fb_data_queries.js +354 -0
- package/dist/utils/fb_data_queries.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/issue_bucketing.d.ts +36 -0
- package/dist/utils/issue_bucketing.d.ts.map +1 -0
- package/dist/utils/issue_bucketing.js +107 -0
- package/dist/utils/issue_bucketing.js.map +1 -0
- package/dist/utils/validation_result.d.ts +32 -0
- package/dist/utils/validation_result.d.ts.map +1 -0
- package/dist/utils/validation_result.js +55 -0
- package/dist/utils/validation_result.js.map +1 -0
- package/package.json +16 -4
|
@@ -10,7 +10,7 @@ const EMPTY_CLARIFICATIONS = [];
|
|
|
10
10
|
const EMPTY_REVIEW_DECISIONS = new Map();
|
|
11
11
|
const EMPTY_STRING_SET = new Set();
|
|
12
12
|
const EMPTY_PENDING_RESPONSES = new Map();
|
|
13
|
-
export function use_fb_form_state(props, active_instance_id, active_instance, pending_clarification_responses) {
|
|
13
|
+
export function use_fb_form_state(props, active_instance_id, active_instance, pending_clarification_responses, form_data_entries) {
|
|
14
14
|
const logger = use_logger();
|
|
15
15
|
const [active_tab, set_active_tab_raw] = useState(props.initial_tab ?? 'front');
|
|
16
16
|
const set_active_tab = useCallback((tab) => {
|
|
@@ -209,14 +209,35 @@ export function use_fb_form_state(props, active_instance_id, active_instance, pe
|
|
|
209
209
|
const set_active_step = useCallback((step) => {
|
|
210
210
|
set_active_step_raw(step);
|
|
211
211
|
}, []);
|
|
212
|
-
|
|
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]);
|
|
213
235
|
// Track whether review was completed (persists even when draft_clarifications empty out after processing)
|
|
214
236
|
const [review_was_completed, set_review_was_completed] = useState(false);
|
|
215
237
|
const [confirmed_send_back_count, set_confirmed_send_back_count] = useState(0);
|
|
216
238
|
// Snapshot of review items at time of confirmation (survives draft_clarifications clearing)
|
|
217
239
|
const [confirmed_review_items, set_confirmed_review_items] = useState([]);
|
|
218
240
|
const [confirmed_send_back_items, set_confirmed_send_back_items] = useState([]);
|
|
219
|
-
const [send_back_comments, set_send_back_comments] = useState(new Map());
|
|
220
241
|
// Build review queue items from draft clarifications
|
|
221
242
|
const effective_pending = pending_clarification_responses ?? EMPTY_PENDING_RESPONSES;
|
|
222
243
|
const review_queue_items = useMemo(() => {
|
|
@@ -227,14 +248,33 @@ export function use_fb_form_state(props, active_instance_id, active_instance, pe
|
|
|
227
248
|
const front_clrs = Array.isArray(props.front_form_data?.['__clarifications'])
|
|
228
249
|
? props.front_form_data['__clarifications'].filter(c => c.status === 'responded' && c.thread && c.thread.length > 0)
|
|
229
250
|
: [];
|
|
230
|
-
// Combine all sources
|
|
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).
|
|
231
255
|
const draft_ids = new Set(draft_clarifications.map(c => c.id));
|
|
232
|
-
const
|
|
233
|
-
const all_items = [
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|
+
}
|
|
238
278
|
return all_items.map((clr) => {
|
|
239
279
|
// Determine category from classification results
|
|
240
280
|
let category = 'uncategorized';
|
|
@@ -356,9 +396,104 @@ export function use_fb_form_state(props, active_instance_id, active_instance, pe
|
|
|
356
396
|
// Enrich clarification with resolved response data for views to access
|
|
357
397
|
const needs_enrichment = (response_choice || user_comment) && (!clr.response_choice && !clr.user_comment);
|
|
358
398
|
const needs_status_update = enriched_status !== clr.status;
|
|
359
|
-
|
|
399
|
+
let enriched_clr = (needs_enrichment || needs_status_update)
|
|
360
400
|
? { ...clr, ...(needs_enrichment ? { response_choice, user_comment } : {}), ...(needs_status_update ? { status: enriched_status } : {}) }
|
|
361
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
|
+
}
|
|
362
497
|
return {
|
|
363
498
|
id: clr.id,
|
|
364
499
|
category,
|
|
@@ -371,7 +506,7 @@ export function use_fb_form_state(props, active_instance_id, active_instance, pe
|
|
|
371
506
|
decision: review_queue_decisions.get(clr.id),
|
|
372
507
|
};
|
|
373
508
|
});
|
|
374
|
-
}, [draft_clarifications, classification_results, props.available_tags, review_queue_decisions, file_validation_results, sent_clarifications, effective_pending, props.front_form_data]);
|
|
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]);
|
|
375
510
|
// Use live items if available, otherwise fall back to confirmed snapshot
|
|
376
511
|
const effective_review_items = review_queue_items.length > 0 ? review_queue_items : confirmed_review_items;
|
|
377
512
|
// Computed: all items have decisions (or no items exist)
|
|
@@ -381,18 +516,96 @@ export function use_fb_form_state(props, active_instance_id, active_instance, pe
|
|
|
381
516
|
return effective_review_items.every((item) => review_queue_decisions.has(item.id));
|
|
382
517
|
}, [effective_review_items, review_queue_decisions]);
|
|
383
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';
|
|
384
520
|
const send_back_items = useMemo(() => {
|
|
385
521
|
const live = effective_review_items.filter((item) => review_queue_decisions.get(item.id) === 'send_back');
|
|
386
|
-
|
|
387
|
-
|
|
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]);
|
|
388
595
|
// Computed: step configurations
|
|
389
596
|
// Steps stay visible once they've been active — even if the underlying data clears after processing
|
|
390
597
|
const step_configs = useMemo(() => {
|
|
391
598
|
const has_review_items = effective_review_items.length > 0;
|
|
392
599
|
const undecided_count = effective_review_items.filter((item) => !review_queue_decisions.has(item.id)).length;
|
|
393
600
|
const labels = props.stepper_labels ?? {};
|
|
394
|
-
|
|
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;
|
|
395
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'));
|
|
396
609
|
return [
|
|
397
610
|
{
|
|
398
611
|
id: 'review',
|
|
@@ -413,10 +626,10 @@ export function use_fb_form_state(props, active_instance_id, active_instance, pe
|
|
|
413
626
|
label: labels.send_back ?? 'Send Back',
|
|
414
627
|
badge_count: send_back_items.length || confirmed_send_back_count,
|
|
415
628
|
enabled: send_back_enabled,
|
|
416
|
-
completed:
|
|
629
|
+
completed: is_completed_instance && (has_v2_sent_back || sent_clarifications.length > 0),
|
|
417
630
|
},
|
|
418
631
|
];
|
|
419
|
-
}, [review_queue_items, review_queue_decisions, review_complete, send_back_items, props.stepper_labels, review_was_completed, confirmed_send_back_count]);
|
|
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]);
|
|
420
633
|
// Confirm review decisions: map to existing review_decisions, collect accepted file IDs, and advance step.
|
|
421
634
|
// Returns accepted file IDs so callers can trigger routing/autofill.
|
|
422
635
|
const confirm_review_decisions = useCallback(() => {
|
|
@@ -431,14 +644,28 @@ export function use_fb_form_state(props, active_instance_id, active_instance, pe
|
|
|
431
644
|
}));
|
|
432
645
|
set_confirmed_review_items(items_with_comments);
|
|
433
646
|
set_confirmed_send_back_items(items_with_comments.filter(i => review_queue_decisions.get(i.id) === 'send_back'));
|
|
434
|
-
// Collect accepted file IDs for routing
|
|
647
|
+
// Collect accepted file IDs for routing — includes original doc_references AND response files
|
|
435
648
|
const accepted_file_ids = [];
|
|
649
|
+
const seen_ids = new Set();
|
|
436
650
|
for (const [item_id, decision] of review_queue_decisions.entries()) {
|
|
437
651
|
if (decision === 'accept') {
|
|
438
652
|
const item = effective_review_items.find(i => i.id === item_id);
|
|
653
|
+
// Original file from doc_references
|
|
439
654
|
const file_id = item?.clarification?.doc_references?.[0]?.file_id;
|
|
440
|
-
if (file_id)
|
|
655
|
+
if (file_id && !seen_ids.has(file_id)) {
|
|
656
|
+
seen_ids.add(file_id);
|
|
441
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
|
+
}
|
|
442
669
|
}
|
|
443
670
|
}
|
|
444
671
|
// Add accepted files to skipped_file_ids (consistent with clarifications_view skip_process flow)
|
|
@@ -483,62 +710,120 @@ export function use_fb_form_state(props, active_instance_id, active_instance, pe
|
|
|
483
710
|
set_active_step_raw('tax_data');
|
|
484
711
|
return accepted_file_ids;
|
|
485
712
|
}, [review_queue_decisions, set_review_decisions, effective_review_items, send_back_comments, set_skipped_file_ids, set_file_validation_results]);
|
|
486
|
-
// ── Restore review decisions from
|
|
487
|
-
//
|
|
488
|
-
//
|
|
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.
|
|
489
716
|
const has_restored_decisions = useRef(new Set());
|
|
490
717
|
useEffect(() => {
|
|
491
|
-
// Only restore once per instance key (avoid re-running after user makes new decisions)
|
|
492
718
|
if (has_restored_decisions.current.has(instance_key))
|
|
493
719
|
return;
|
|
494
|
-
//
|
|
720
|
+
// With per-instance keying, each instance starts with an empty Map.
|
|
721
|
+
// Only restore if the instance's Map is actually empty.
|
|
495
722
|
if (review_queue_decisions.size > 0) {
|
|
496
723
|
has_restored_decisions.current.add(instance_key);
|
|
497
724
|
return;
|
|
498
725
|
}
|
|
499
|
-
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
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
|
+
}
|
|
505
748
|
}
|
|
506
749
|
}
|
|
507
|
-
if
|
|
508
|
-
|
|
509
|
-
// Build
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
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
|
+
}
|
|
529
778
|
}
|
|
530
779
|
}
|
|
531
780
|
if (restored.size > 0) {
|
|
532
781
|
has_restored_decisions.current.add(instance_key);
|
|
533
782
|
set_review_queue_decisions(restored);
|
|
534
783
|
set_review_was_completed(true);
|
|
784
|
+
if (restored_comments.size > 0)
|
|
785
|
+
set_send_back_comments(restored_comments);
|
|
535
786
|
logger.info('[use_fb_form_state] restored_review_decisions', {
|
|
536
787
|
instance_key,
|
|
537
788
|
restored_count: restored.size,
|
|
538
|
-
|
|
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;
|
|
539
824
|
});
|
|
540
825
|
}
|
|
541
|
-
}, [
|
|
826
|
+
}, [form_data_entries]);
|
|
542
827
|
const stepper_snapshots = useRef({});
|
|
543
828
|
const prev_stepper_instance_id = useRef(active_instance_id);
|
|
544
829
|
useEffect(() => {
|
|
@@ -549,12 +834,10 @@ export function use_fb_form_state(props, active_instance_id, active_instance, pe
|
|
|
549
834
|
if (prev_id && prev_id !== active_instance_id) {
|
|
550
835
|
stepper_snapshots.current[prev_id] = {
|
|
551
836
|
step: active_step,
|
|
552
|
-
decisions: review_queue_decisions,
|
|
553
837
|
was_completed: review_was_completed,
|
|
554
838
|
send_back_count: confirmed_send_back_count,
|
|
555
839
|
review_items: confirmed_review_items,
|
|
556
840
|
send_back_items: confirmed_send_back_items,
|
|
557
|
-
comments: send_back_comments,
|
|
558
841
|
};
|
|
559
842
|
}
|
|
560
843
|
prev_stepper_instance_id.current = active_instance_id;
|
|
@@ -562,14 +845,12 @@ export function use_fb_form_state(props, active_instance_id, active_instance, pe
|
|
|
562
845
|
const saved = active_instance_id ? stepper_snapshots.current[active_instance_id] : undefined;
|
|
563
846
|
if (saved) {
|
|
564
847
|
set_active_step_raw(saved.step);
|
|
565
|
-
set_review_queue_decisions(saved.decisions);
|
|
566
848
|
set_review_was_completed(saved.was_completed);
|
|
567
849
|
set_confirmed_send_back_count(saved.send_back_count);
|
|
568
850
|
set_confirmed_review_items(saved.review_items);
|
|
569
851
|
set_confirmed_send_back_items(saved.send_back_items);
|
|
570
|
-
set_send_back_comments(saved.comments);
|
|
571
852
|
}
|
|
572
|
-
else {
|
|
853
|
+
else if (!has_restored_decisions.current.has(instance_key ?? '')) {
|
|
573
854
|
// Fresh initialization
|
|
574
855
|
if (review_queue_items.length === 0) {
|
|
575
856
|
set_active_step_raw('tax_data');
|
|
@@ -577,12 +858,10 @@ export function use_fb_form_state(props, active_instance_id, active_instance, pe
|
|
|
577
858
|
else {
|
|
578
859
|
set_active_step_raw('review');
|
|
579
860
|
}
|
|
580
|
-
set_review_queue_decisions(new Map());
|
|
581
861
|
set_review_was_completed(false);
|
|
582
862
|
set_confirmed_send_back_count(0);
|
|
583
863
|
set_confirmed_review_items([]);
|
|
584
864
|
set_confirmed_send_back_items([]);
|
|
585
|
-
set_send_back_comments(new Map());
|
|
586
865
|
}
|
|
587
866
|
}, [props.agent_stepper, active_instance_id]);
|
|
588
867
|
return {
|