From 76063b54cf1ccd7f3d9d9e602902479c9e553868 Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Mon, 17 Jul 2023 17:03:29 -0400 Subject: [PATCH 01/87] APPEALS-24996 Create new file for modal component --- .../CreateHearingPostponementMailRequestModal.jsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 client/app/queue/CreateHearingPostponementMailRequestModal.jsx diff --git a/client/app/queue/CreateHearingPostponementMailRequestModal.jsx b/client/app/queue/CreateHearingPostponementMailRequestModal.jsx new file mode 100644 index 00000000000..8ae82f14532 --- /dev/null +++ b/client/app/queue/CreateHearingPostponementMailRequestModal.jsx @@ -0,0 +1,13 @@ +import React from "react"; +import QueueFlowModal from "./components/QueueFlowModal"; + +const CreateHearingPostponementMailRequestModal = (props) => { + + return ( + + + + ) +} + +export default CreateHearingPostponementMailRequestModal; From 89e2334e2f6706335f4730d48db0a764ea716b6c Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Thu, 20 Jul 2023 12:16:39 -0400 Subject: [PATCH 02/87] APPEALS-24996 Create EfolderUrlField component and add to HPR version of CreateMailTask --- client/app/queue/CreateMailTaskDialog.jsx | 18 +++++++++- .../app/queue/components/EfolderUrlField.jsx | 36 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 client/app/queue/components/EfolderUrlField.jsx diff --git a/client/app/queue/CreateMailTaskDialog.jsx b/client/app/queue/CreateMailTaskDialog.jsx index ba356b0ac2d..b36cc070e3d 100644 --- a/client/app/queue/CreateMailTaskDialog.jsx +++ b/client/app/queue/CreateMailTaskDialog.jsx @@ -9,6 +9,7 @@ import COPY from '../../COPY'; import { onReceiveAmaTasks } from './QueueActions'; import SearchableDropdown from '../components/SearchableDropdown'; import TextareaField from '../components/TextareaField'; +import EfolderUrlField from './components/EfolderUrlField'; import { requestSave } from './uiReducer/uiActions'; import { taskById, appealWithDetailSelector } from './selectors'; import QueueFlowModal from './components/QueueFlowModal'; @@ -34,12 +35,17 @@ export class CreateMailTaskDialog extends React.Component { this.state = { selectedValue: null, instructions: '', + eFolderUrl: '' }; } validateForm = () => this.state.selectedValue !== null && this.state.instructions !== ''; + prependUrlToInstructions = () => ( + this.isHearingRequestMailTask ? (`${this.state.eFolderUrl} - ${this.state.instructions}`) : this.state.instructions + ); + submit = () => { const { appeal, task } = this.props; @@ -50,7 +56,7 @@ export class CreateMailTaskDialog extends React.Component { type: this.state.selectedValue, external_id: appeal.externalId, parent_id: task.taskId, - instructions: this.state.instructions, + instructions: this.prependUrlToInstructions(), }, ], }, @@ -81,6 +87,8 @@ export class CreateMailTaskDialog extends React.Component { throw new Error('Task action requires data'); }; + isHearingRequestMailTask = () => (this.state.selectedValue || '').match(/Hearing.*RequestMailTask/); + render = () => { const { highlightFormItems, task } = this.props; @@ -112,6 +120,14 @@ export class CreateMailTaskDialog extends React.Component { options={this.taskActionData().options} />
+ { + this.isHearingRequestMailTask() && + this.setState({ eFolderUrl: value })} + value={this.state.eFolderUrl} + /> + } { + + const extractRequestType = () => ( + props.requestType.replace('Hearing', '').replace('RequestMailTask', ''). + toLowerCase() + ); + + const handleChange = (value) => { + props?.onChange?.(value); + }; + + return <> + + ; +}; + +EfolderUrlField.propTypes = { + requestType: PropTypes.string, + value: PropTypes.string +}; + +export default EfolderUrlField; From 3b549d4e553fb8bcac7e0af4e1a37351e9331bf5 Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Thu, 20 Jul 2023 12:17:05 -0400 Subject: [PATCH 03/87] APPEALS-24996 Delete incorrectly created component --- .../CreateHearingPostponementMailRequestModal.jsx | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 client/app/queue/CreateHearingPostponementMailRequestModal.jsx diff --git a/client/app/queue/CreateHearingPostponementMailRequestModal.jsx b/client/app/queue/CreateHearingPostponementMailRequestModal.jsx deleted file mode 100644 index 8ae82f14532..00000000000 --- a/client/app/queue/CreateHearingPostponementMailRequestModal.jsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from "react"; -import QueueFlowModal from "./components/QueueFlowModal"; - -const CreateHearingPostponementMailRequestModal = (props) => { - - return ( - - - - ) -} - -export default CreateHearingPostponementMailRequestModal; From 4462f889161f7755da480a08e3d34fc103e3bab8 Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Fri, 21 Jul 2023 16:21:58 -0400 Subject: [PATCH 04/87] APPEALS-24996 Added error messaging, updated validation, disabled submit button --- client/app/queue/CreateMailTaskDialog.jsx | 20 ++++++++++++++++--- .../app/queue/components/EfolderUrlField.jsx | 4 +++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/client/app/queue/CreateMailTaskDialog.jsx b/client/app/queue/CreateMailTaskDialog.jsx index b36cc070e3d..0a5d48a9641 100644 --- a/client/app/queue/CreateMailTaskDialog.jsx +++ b/client/app/queue/CreateMailTaskDialog.jsx @@ -39,11 +39,18 @@ export class CreateMailTaskDialog extends React.Component { }; } - validateForm = () => - this.state.selectedValue !== null && this.state.instructions !== ''; + validateForm = () => { + const instructionsAndValue = () => this.state.selectedValue !== null && this.state.instructions !== ''; + + if (this.isHearingRequestMailTask()) { + return instructionsAndValue() && this.state.eFolderUrl !== ''; + } + + return instructionsAndValue(); + } prependUrlToInstructions = () => ( - this.isHearingRequestMailTask ? (`${this.state.eFolderUrl} - ${this.state.instructions}`) : this.state.instructions + this.isHearingRequestMailTask() ? (`${this.state.eFolderUrl} - ${this.state.instructions}`) : this.state.instructions ); submit = () => { @@ -102,6 +109,7 @@ export class CreateMailTaskDialog extends React.Component { validateForm={this.validateForm} title={COPY.CREATE_MAIL_TASK_TITLE} pathAfterSubmit={`/queue/appeals/${this.props.appealId}`} + submitDisabled={!this.validateForm()} > this.setState({ eFolderUrl: value })} value={this.state.eFolderUrl} /> diff --git a/client/app/queue/components/EfolderUrlField.jsx b/client/app/queue/components/EfolderUrlField.jsx index f55a748a4e1..c93f2a72158 100644 --- a/client/app/queue/components/EfolderUrlField.jsx +++ b/client/app/queue/components/EfolderUrlField.jsx @@ -24,13 +24,15 @@ const EfolderUrlField = (props) => { name="meaninglessName" value={props.value} onChange={handleChange} + errorMessage={props.errorMessage} /> ; }; EfolderUrlField.propTypes = { requestType: PropTypes.string, - value: PropTypes.string + value: PropTypes.string, + errorMessage: PropTypes.string }; export default EfolderUrlField; From d73d0459643f82739be3cf4a4794e11822d92bca Mon Sep 17 00:00:00 2001 From: jefftmarks <106996298+jefftmarks@users.noreply.github.com> Date: Tue, 25 Jul 2023 16:14:31 -0400 Subject: [PATCH 05/87] jefftmarks/APPEALS-24994-24995 (#19018) * Updated comment list of tasks in MailTask * APPEALS-24994 created HearingRequestMailTask * APPEALS-24992 Added verification to prevent creation of HearingRequestMailTask * APPEALS 24994 Added comments to HearingRequestMailTask * Updated comments on HearingRequestMailTask * APPEALS-24994 Completed HearingPostponementRequestMailTask * APPEALS-24995 added factory and traits for HearingPostponementRequestMailTask * APPEALS-24994 Added HPR to TASK_CLASSES_LOOKUP hash and changed 'subclasses' to 'descendants' in MailTask * APPEALS-24994 fixed typo * APPEALS-24995 replaced placeholder class with HearingPostponementRequestMailTask * APPEALS-24994 Created alias for descendant/subclass * APPEALS-24995 changed assigned_to to hearing admin * APPEALS-24994 swapped out alias and changed subclass to descendant in task action repository * APPEALS-24994 set blocking to true on HPR to force distribution task as parent * APPEALS-24994 Created unit test for HearingRequestMailTask * APPEALS-24995 refactored and fixed factory methods * APPEALS-24994 Completed unit tests for HPR mail task * APPEALS-24994 removed byebug from tasks spec and added new context to HPR mail task spec * Refactored before_validation check on HearingRequestMailTask * Rephrased unit test example names * APPEALS-24995 parent task is now root task * APPEALS-24994 Changed comment * APPEALS-24995 adjusted task tree to have child hearing postponement task * APPEALS-24994 Refactored open assign hearing task to account for tasks without hearings * APPEALS-24994 updated comments * APPEALS-24994 reverted task_spec back to original * APPEALS-24994 updated mail_task_spec subclass_routing_options to descendant_routing_options * APPEALS-24994 removed comment for validation on HearingRequestMailTask * APPEALS-24994 add question mark to method name * APPEALS-24944 swapped in Hearing#scheduled_in_past? method * APPEALS-24994 refactored spec to add context for AMA appeal * APPEALS-24995 added distribution task to task tree in factory * APPEALS-24994 condensed comments * APPEALS-24994 fixed linting * APPEALS-24995 fixed ordering of tree * APPEALS-24995 workaround found without updating task IDs --------- Co-authored-by: Minhazur Rahaman --- app/controllers/tasks_controller.rb | 1 + .../hearing_postponement_request_mail_task.rb | 59 ++++++++++ .../hearing_request_mail_task.rb | 41 +++++++ app/models/tasks/mail_task.rb | 8 +- app/repositories/task_action_repository.rb | 2 +- client/COPY.json | 1 + client/constants/TASK_ACTIONS.json | 4 + lib/caseflow/error.rb | 8 ++ spec/factories/task.rb | 35 ++++++ spec/feature/queue/mail_task_spec.rb | 2 +- ...ing_postponement_request_mail_task_spec.rb | 101 ++++++++++++++++++ .../hearing_request_mail_task_spec.rb | 14 +++ 12 files changed, 271 insertions(+), 5 deletions(-) create mode 100644 app/models/tasks/hearing_mail_tasks/hearing_postponement_request_mail_task.rb create mode 100644 app/models/tasks/hearing_mail_tasks/hearing_request_mail_task.rb create mode 100644 spec/models/tasks/hearing_mail_tasks/hearing_postponement_request_mail_task_spec.rb create mode 100644 spec/models/tasks/hearing_mail_tasks/hearing_request_mail_task_spec.rb diff --git a/app/controllers/tasks_controller.rb b/app/controllers/tasks_controller.rb index 2aebe30f96f..7cadcde95aa 100644 --- a/app/controllers/tasks_controller.rb +++ b/app/controllers/tasks_controller.rb @@ -30,6 +30,7 @@ class TasksController < ApplicationController EducationDocumentSearchTask: EducationDocumentSearchTask, FoiaTask: FoiaTask, HearingAdminActionTask: HearingAdminActionTask, + HearingPostponementRequestMailTask: HearingPostponementRequestMailTask, InformalHearingPresentationTask: InformalHearingPresentationTask, JudgeAddressMotionToVacateTask: JudgeAddressMotionToVacateTask, JudgeAssignTask: JudgeAssignTask, diff --git a/app/models/tasks/hearing_mail_tasks/hearing_postponement_request_mail_task.rb b/app/models/tasks/hearing_mail_tasks/hearing_postponement_request_mail_task.rb new file mode 100644 index 00000000000..eea9f98edc2 --- /dev/null +++ b/app/models/tasks/hearing_mail_tasks/hearing_postponement_request_mail_task.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +## +# Task to process a hearing postponement request received via the mail +# +# When this task is created: +# - It's parent task is set as the RootTask of the associated appeal +# - The task is assigned to the MailTeam to track where the request originated +# - A child task of the same name is created and assigned to the HearingAdmin organization +## +class HearingPostponementRequestMailTask < HearingRequestMailTask + class << self + def label + COPY::HEARING_POSTPONEMENT_REQUEST_MAIL_TASK_LABEL + end + + def allow_creation?(*) + true + end + end + + TASK_ACTIONS = [ + Constants.TASK_ACTIONS.CHANGE_TASK_TYPE.to_h, + Constants.TASK_ACTIONS.COMPLETE_AND_POSTPONE.to_h, + Constants.TASK_ACTIONS.ASSIGN_TO_TEAM.to_h, + Constants.TASK_ACTIONS.ASSIGN_TO_PERSON.to_h, + Constants.TASK_ACTIONS.CANCEL_TASK.to_h + ].freeze + + def available_actions(user) + return [] unless user.in_hearing_admin_team? + + if active_schedule_hearing_task? || open_assign_hearing_disposition_task? + TASK_ACTIONS + else + [ + Constants.TASK_ACTIONS.CHANGE_TASK_TYPE.to_h, + Constants.TASK_ACTIONS.CANCEL_TASK.to_h + ] + end + end + + private + + def active_schedule_hearing_task? + appeal.tasks.where(type: ScheduleHearingTask.name).active.any? + end + + def open_assign_hearing_disposition_task? + # ChangeHearingDispositionTask is a subclass of AssignHearingDispositionTask + disposition_task_names = [AssignHearingDispositionTask.name, ChangeHearingDispositionTask.name] + open_task = appeal.tasks.where(type: disposition_task_names).open.first + + return false unless open_task&.hearing + + # Ensure hearing associated with AssignHearingDispositionTask is not scheduled in the past + !open_task.hearing.scheduled_for_past? + end +end diff --git a/app/models/tasks/hearing_mail_tasks/hearing_request_mail_task.rb b/app/models/tasks/hearing_mail_tasks/hearing_request_mail_task.rb new file mode 100644 index 00000000000..ed409c91747 --- /dev/null +++ b/app/models/tasks/hearing_mail_tasks/hearing_request_mail_task.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +## +# Task to serve as interface with shared methods for the following hearings mail tasks: +# - HearingPostponementRequestMailTask +# - HearingWithdrawalRequestMailTask +# HearingRequestMailTask is itself not an assignable task type +## +class HearingRequestMailTask < MailTask + validates :parent, presence: true, on: :create + + before_validation :verify_request_type_designated + + class << self + def allow_creation?(*) + false + end + + # All descendant postponement/withdrawal tasks will initially be assigned to the Hearing Admin org + def default_assignee(_task) + HearingAdmin.singleton + end + end + + def available_actions(_user) + [] + end + + def update_from_params(params, current_user) + super(params, current_user) + end + + private + + # Ensure create is called on a descendant mail task and not directly on the HearingRequestMailTask class + def verify_request_type_designated + if self.class == HearingRequestMailTask + fail Caseflow::Error::InvalidTaskTypeOnTaskCreate, task_type: type + end + end +end diff --git a/app/models/tasks/mail_task.rb b/app/models/tasks/mail_task.rb index 9e68708bd59..a0879242381 100644 --- a/app/models/tasks/mail_task.rb +++ b/app/models/tasks/mail_task.rb @@ -10,6 +10,8 @@ # - withdrawing an appeal # - switching dockets # - add post-decision motions +# - postponing a hearing +# - withdrawing a hearing # Adding a mail task to an appeal is done by mail team members and will create a task assigned to the mail team. It # will also automatically create a child task assigned to the team the task should be routed to. @@ -21,12 +23,12 @@ def verify_org_task_unique; end class << self def blocking? # Some open mail tasks should block distribution of an appeal to judges. - # Define this method in subclasses for blocking task types. + # Define this method in descendants for blocking task types. false end - def subclass_routing_options(user: nil, appeal: nil) - filtered = MailTask.subclasses.select { |sc| sc.allow_creation?(user: user, appeal: appeal) } + def descendant_routing_options(user: nil, appeal: nil) + filtered = MailTask.descendants.select { |sc| sc.allow_creation?(user: user, appeal: appeal) } sorted = filtered.sort_by(&:label).map { |subclass| { value: subclass.name, label: subclass.label } } sorted end diff --git a/app/repositories/task_action_repository.rb b/app/repositories/task_action_repository.rb index 8701aa36a68..23c321fdb59 100644 --- a/app/repositories/task_action_repository.rb +++ b/app/repositories/task_action_repository.rb @@ -18,7 +18,7 @@ def assign_to_organization_data(task, _user = nil) end def mail_assign_to_organization_data(task, user = nil) - options = MailTask.subclass_routing_options(user: user, appeal: task.appeal) + options = MailTask.descendant_routing_options(user: user, appeal: task.appeal) valid_options = task.appeal.outcoded? ? options : options.reject { |opt| opt[:value] == "VacateMotionMailTask" } { options: valid_options } end diff --git a/client/COPY.json b/client/COPY.json index 9bd85705be1..418b2b4433d 100644 --- a/client/COPY.json +++ b/client/COPY.json @@ -816,6 +816,7 @@ "EXTENSION_REQUEST_MAIL_TASK_LABEL": "Extension request", "FOIA_REQUEST_MAIL_TASK_LABEL": "FOIA request", "HEARING_RELATED_MAIL_TASK_LABEL": "Hearing-related", + "HEARING_POSTPONEMENT_REQUEST_MAIL_TASK_LABEL": "Hearing postponement request", "OTHER_MOTION_MAIL_TASK_LABEL": "Other motion", "POWER_OF_ATTORNEY_MAIL_TASK_LABEL": "Power of attorney-related", "PRIVACY_ACT_REQUEST_MAIL_TASK_LABEL": "Privacy act request", diff --git a/client/constants/TASK_ACTIONS.json b/client/constants/TASK_ACTIONS.json index 03bb26fdaa7..7967b02cd90 100644 --- a/client/constants/TASK_ACTIONS.json +++ b/client/constants/TASK_ACTIONS.json @@ -529,5 +529,9 @@ "label": "Proceed to final notification letter", "value": "modal/proceed_final_notification_letter_post_holding", "func": "proceed_final_notification_letter_data" + }, + "COMPLETE_AND_POSTPONE": { + "label": "Mark as complete", + "value": "modal/complete_and_postpone" } } diff --git a/lib/caseflow/error.rb b/lib/caseflow/error.rb index df77673dd3b..b9e75e3934e 100644 --- a/lib/caseflow/error.rb +++ b/lib/caseflow/error.rb @@ -104,6 +104,14 @@ def initialize(args) end end + class InvalidTaskTypeOnTaskCreate < SerializableError + def initialize(args) + @task_type = args[:task_type] + @code = args[:code] || 400 + @message = args[:message] || "#{@task_type} is not an assignable task type" + end + end + # :reek:TooManyInstanceVariables class MultipleOpenTasksOfSameTypeError < SerializableError def initialize(args) diff --git a/spec/factories/task.rb b/spec/factories/task.rb index ae31e30d050..20157d3086c 100644 --- a/spec/factories/task.rb +++ b/spec/factories/task.rb @@ -88,6 +88,36 @@ def self.find_first_task_or_create(appeal, task_type, **kwargs) end end + trait :with_unscheduled_hearing do + after(:create) do |task| + appeal = task.appeal + root_task = appeal.root_task + distro_task = task.parent + task.update!(parent: root_task) + ScheduleHearingTask.create!(appeal: appeal, parent: distro_task, assigned_to: Bva.singleton) + HearingPostponementRequestMailTask.create!(appeal: appeal, parent: task, + assigned_to: HearingAdmin.singleton) + end + end + + trait :with_scheduled_hearing do + after(:create) do |task| + appeal = task.appeal + root_task = appeal.root_task + distro_task = task.parent + task.update!(parent: root_task) + schedule_hearing_task = ScheduleHearingTask.create!(appeal: appeal, parent: distro_task, + assigned_to: Bva.singleton) + schedule_hearing_task.update(status: "completed", closed_at: Time.zone.now) + hearing = create(:hearing, disposition: nil, judge: nil, appeal: appeal) + distro_task.update!(status: "on_hold") + AssignHearingDispositionTask.create!(appeal: appeal, parent: schedule_hearing_task.parent, + assigned_to: Bva.singleton) + HearingTaskAssociation.create!(hearing: hearing, hearing_task: schedule_hearing_task.parent) + HearingPostponementRequestMailTask.create!(appeal: appeal, parent: task, assigned_to: HearingAdmin.singleton) + end + end + # Colocated tasks for Legacy appeals factory :colocated_task, traits: [ColocatedTask.actions_assigned_to_colocated.sample.to_sym] do # don't expect to have a parent for LegacyAppeals @@ -628,6 +658,11 @@ def self.find_first_task_or_create(appeal, task_type, **kwargs) create(:user, full_name: "Motions Attorney", css_id: "LIT_SUPPORT_ATTY_1") end end + + factory :hearing_postponement_request_mail_task, class: HearingPostponementRequestMailTask do + parent { create(:distribution_task, appeal: appeal) } + assigned_to { MailTeam.singleton } + end end end end diff --git a/spec/feature/queue/mail_task_spec.rb b/spec/feature/queue/mail_task_spec.rb index 2ab7dcddf3e..92780617d37 100644 --- a/spec/feature/queue/mail_task_spec.rb +++ b/spec/feature/queue/mail_task_spec.rb @@ -109,7 +109,7 @@ expect(page).to have_content(COPY::CHANGE_TASK_TYPE_SUBHEAD) # Ensure all admin actions are available - mail_tasks = MailTask.subclass_routing_options + mail_tasks = MailTask.descendant_routing_options find(".cf-select__control", text: "Select an action type").click do visible_options = page.find_all(".cf-select__option") expect(visible_options.length).to eq mail_tasks.length diff --git a/spec/models/tasks/hearing_mail_tasks/hearing_postponement_request_mail_task_spec.rb b/spec/models/tasks/hearing_mail_tasks/hearing_postponement_request_mail_task_spec.rb new file mode 100644 index 00000000000..638cf2c6c88 --- /dev/null +++ b/spec/models/tasks/hearing_mail_tasks/hearing_postponement_request_mail_task_spec.rb @@ -0,0 +1,101 @@ +# frozen_string_literal: true + +describe HearingPostponementRequestMailTask, :postgres do + let(:user) { create(:user) } + + context "The hearing is associated with an AMA appeal" do + describe "#available_actions" do + let(:task_actions) do + [ + Constants.TASK_ACTIONS.CHANGE_TASK_TYPE.to_h, + Constants.TASK_ACTIONS.COMPLETE_AND_POSTPONE.to_h, + Constants.TASK_ACTIONS.ASSIGN_TO_TEAM.to_h, + Constants.TASK_ACTIONS.ASSIGN_TO_PERSON.to_h, + Constants.TASK_ACTIONS.CANCEL_TASK.to_h + ] + end + let(:reduced_task_actions) do + [ + Constants.TASK_ACTIONS.CHANGE_TASK_TYPE.to_h, + Constants.TASK_ACTIONS.CANCEL_TASK.to_h + ] + end + + context "when user does not belong to the hearing admin team" do + it "returns an empty array" do + expect(subject.available_actions(user).length).to eq(0) + end + end + + context "when user belongs to the hearing admin team" do + before { HearingAdmin.singleton.add_user(user) } + + shared_examples "returns appropriate task actions" do + it "returns appropriate task actions" do + expect(hpr.available_actions(user).length).to eq(5) + expect(hpr.available_actions(user)).to eq(task_actions) + end + end + + shared_examples "returns appropriate reduced task actions" do + it "returns appropriate reduced task actions" do + expect(hpr.available_actions(user).length).to eq(2) + expect(hpr.available_actions(user)).to eq(reduced_task_actions) + end + end + + context "when there is an active ScheduleHearingTask in the appeal's task tree" do + let(:hpr) { create(:hearing_postponement_request_mail_task, :with_unscheduled_hearing) } + + include_examples "returns appropriate task actions" + end + + context "when there is an open AssignHearingDispositionTask in the appeal's task tree" do + let(:hpr) { create(:hearing_postponement_request_mail_task, :with_scheduled_hearing) } + + context "when the hearing is scheduled in the past" do + before do + allow_any_instance_of(Hearing).to receive(:scheduled_for).and_return(Time.zone.yesterday) + end + + include_examples "returns appropriate reduced task actions" + end + + context "when the hearing is not scheduled in the past" do + before do + allow_any_instance_of(Hearing).to receive(:scheduled_for).and_return(Time.zone.tomorrow) + end + + include_examples "returns appropriate task actions" + + context "when there is a child ChangeHearingDispositionTask in the appeal's task tree" do + let(:appeal) { hpr.appeal } + let(:disposition_task) { appeal.tasks.find_by(type: AssignHearingDispositionTask.name) } + let(:hearing_task) { appeal.tasks.find_by(type: HearingTask.name) } + + before do + disposition_task.update!(status: "completed", closed_at: Time.zone.now) + ChangeHearingDispositionTask.create!(appeal: appeal, parent: hearing_task, + assigned_to: HearingAdmin.singleton) + end + + include_examples "returns appropriate task actions" + end + end + end + + context "when there is neither an active ScheduleHearingTask " \ + "nor an open AssignHearingDispositionTask in the appeal's task tree" do + let(:hpr) { create(:hearing_postponement_request_mail_task, :with_unscheduled_hearing) } + let(:schedul_hearing_task) { hpr.appeal.tasks.find_by(type: ScheduleHearingTask.name) } + + before do + schedul_hearing_task.cancel_task_and_child_subtasks + end + + include_examples "returns appropriate reduced task actions" + end + end + end + end +end diff --git a/spec/models/tasks/hearing_mail_tasks/hearing_request_mail_task_spec.rb b/spec/models/tasks/hearing_mail_tasks/hearing_request_mail_task_spec.rb new file mode 100644 index 00000000000..a5fcced5d0f --- /dev/null +++ b/spec/models/tasks/hearing_mail_tasks/hearing_request_mail_task_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +describe HearingRequestMailTask, :postgres do + let(:user) { create(:user) } + let(:root_task) { create(:root_task) } + + describe ".create" do + let(:params) { { appeal: root_task.appeal, parent: root_task, assigned_to: user } } + + it "throws an error" do + expect { described_class.create!(params) }.to raise_error(Caseflow::Error::InvalidTaskTypeOnTaskCreate) + end + end +end From e02cc8bbe9f1c6855affd346264fd87d42fe82c4 Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Tue, 25 Jul 2023 16:42:19 -0400 Subject: [PATCH 06/87] APPEALS-24996 Basic Jest tests and setup --- .../components/CreateMailTaskDialog.test.js | 81 ++++++++ .../taskActionModals/taskActionModalData.js | 186 ++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 client/test/app/queue/components/CreateMailTaskDialog.test.js diff --git a/client/test/app/queue/components/CreateMailTaskDialog.test.js b/client/test/app/queue/components/CreateMailTaskDialog.test.js new file mode 100644 index 00000000000..6548e41978f --- /dev/null +++ b/client/test/app/queue/components/CreateMailTaskDialog.test.js @@ -0,0 +1,81 @@ +import React from 'react'; +import { MemoryRouter, Route } from 'react-router'; +import { render, screen } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { applyMiddleware, createStore, compose } from 'redux'; +import thunk from 'redux-thunk'; +import COPY from '../../../../COPY'; +import CreateMailTaskDialog from '../../../../app/queue/CreateMailTaskDialog'; +import { + createQueueReducer, + getAppealId, + getTaskId, + enterTextFieldOptions, + enterModalRadioOptions, + selectFromDropdown, + clickSubmissionButton +} from './modalUtils'; +import { rootTaskData } from '../../../data/queue/taskActionModals/taskActionModalData'; +import userEvent from '@testing-library/user-event'; + +const renderCreateMailTaskDialog = (storeValues, taskType) => { + const appealId = getAppealId(storeValues); + const taskId = getTaskId(storeValues, taskType); + + const queueReducer = createQueueReducer(storeValues); + const store = createStore( + queueReducer, + compose(applyMiddleware(thunk)) + ); + + const path = `/queue/appeals/${appealId}/tasks/${taskId}/modal/create_mail_task`; + + return render( + + + { + return ; + }} path="/queue/appeals/:appealId/tasks/:taskId/modal/create_mail_task" /> + + + ); +}; + +describe('CreateMailTaskDialog', () => { + const setUpMailTaskDialog = () => renderCreateMailTaskDialog(rootTaskData, 'RootTask'); + + describe('on modal open', () => { + const modalTitle = 'Create new mail task'; + + test('modal title: "Create new mail task"', () => { + setUpMailTaskDialog(); + + expect(screen.getByText(modalTitle)).toBeTruthy(); + }); + + test('submit button is initially disabled', () =>{ + setUpMailTaskDialog(); + + expect(screen.getByText('Submit')).toBeDisabled(); + }); + }); + + describe('after selecting Hearing Postponement Request', () => { + test('efolder url link field is present', () => { + setUpMailTaskDialog(); + + userEvent.type(screen.getByRole('combobox'), 'Hearing postponement request{enter}'); + + expect(screen.getByLabelText('Include Caseflow Reader document hyperlink to request hearing postponement')). + toBeTruthy(); + }); + + test('instructions field is present', () => { + setUpMailTaskDialog(); + + userEvent.type(screen.getByRole('combobox'), 'Hearing postponement request{enter}'); + + expect(screen.getByLabelText('Provide instructions and context for this action')).toBeTruthy(); + }); + }); +}); diff --git a/client/test/data/queue/taskActionModals/taskActionModalData.js b/client/test/data/queue/taskActionModals/taskActionModalData.js index 56329e28ee5..da0be24d2e2 100644 --- a/client/test/data/queue/taskActionModals/taskActionModalData.js +++ b/client/test/data/queue/taskActionModals/taskActionModalData.js @@ -1787,4 +1787,190 @@ export const camoToProgramOfficeToCamoData = { }, ...uiData, }; + +export const rootTaskData = { + caseList: { + caseListCriteria: { + searchQuery: '' + }, + isRequestingAppealsUsingVeteranId: false, + search: { + errorType: null, + queryResultingInError: null, + errorMessage: null + }, + fetchedAllCasesFor: {} + }, + caseSelect: { + selectedAppealVacolsId: null, + isRequestingAppealsUsingVeteranId: false, + selectedAppeal: {}, + receivedAppeals: [], + search: { + showErrorMessage: false, + noAppealsFoundSearchQueryValue: null + }, + caseSelectCriteria: { + searchQuery: '' + }, + assignments: [], + assignmentsLoaded: false + }, + queue: { + judges: {}, + tasks: {}, + amaTasks: { + 7162: { + uniqueId: '7162', + isLegacy: false, + type: 'RootTask', + appealType: 'Appeal', + addedByCssId: null, + appealId: 1647, + externalAppealId: 'adfd7d18-f848-4df5-9df2-9ca43c58dd13', + assignedOn: '2023-06-21T10:15:02.830-04:00', + closestRegionalOffice: null, + createdAt: '2023-07-25T10:15:02.836-04:00', + closedAt: null, + startedAt: null, + assigneeName: 'Board of Veterans\' Appeals', + assignedTo: { + cssId: null, + name: 'Board of Veterans\' Appeals', + id: 5, + isOrganization: true, + type: 'Bva' + }, + assignedBy: { + firstName: '', + lastName: '', + cssId: null, + pgId: null + }, + cancelledBy: { + cssId: null + }, + convertedOn: null, + taskId: '7162', + parentId: null, + label: 'Root Task', + documentId: null, + externalHearingId: null, + workProduct: null, + placedOnHoldAt: '2023-07-25T10:15:02.851-04:00', + status: 'on_hold', + onHoldDuration: null, + instructions: [], + decisionPreparedBy: null, + availableActions: [ + { + func: 'mail_assign_to_organization_data', + label: 'Create mail task', + value: 'modal/create_mail_task', + data: { + options: [ + { + value: 'CavcCorrespondenceMailTask', + label: 'CAVC Correspondence' + }, + { + value: 'ClearAndUnmistakeableErrorMailTask', + label: 'CUE-related' + }, + { + value: 'AddressChangeMailTask', + label: 'Change of address' + }, + { + value: 'CongressionalInterestMailTask', + label: 'Congressional interest' + }, + { + value: 'ControlledCorrespondenceMailTask', + label: 'Controlled correspondence' + }, + { + value: 'DeathCertificateMailTask', + label: 'Death certificate' + }, + { + value: 'EvidenceOrArgumentMailTask', + label: 'Evidence or argument' + }, + { + value: 'ExtensionRequestMailTask', + label: 'Extension request' + }, + { + value: 'FoiaRequestMailTask', + label: 'FOIA request' + }, + { + value: 'HearingPostponementRequestMailTask', + label: 'Hearing postponement request' + }, + { + value: 'HearingRelatedMailTask', + label: 'Hearing-related' + }, + { + value: 'ReconsiderationMotionMailTask', + label: 'Motion for reconsideration' + }, + { + value: 'AodMotionMailTask', + label: 'Motion to Advance on Docket' + }, + { + value: 'OtherMotionMailTask', + label: 'Other motion' + }, + { + value: 'PowerOfAttorneyRelatedMailTask', + label: 'Power of attorney-related' + }, + { + value: 'PrivacyActRequestMailTask', + label: 'Privacy act request' + }, + { + value: 'PrivacyComplaintMailTask', + label: 'Privacy complaint' + }, + { + value: 'ReturnedUndeliverableCorrespondenceMailTask', + label: 'Returned or undeliverable mail' + }, + { + value: 'StatusInquiryMailTask', + label: 'Status inquiry' + }, + { + value: 'AppealWithdrawalMailTask', + label: 'Withdrawal of appeal' + } + ] + } + } + ], + timelineTitle: 'RootTask completed', + hideFromQueueTableView: false, + hideFromTaskSnapshot: true, + hideFromCaseTimeline: true, + availableHearingLocations: [], + latestInformalHearingPresentationTask: {}, + canMoveOnDocketSwitch: false, + timerEndsAt: null, + unscheduledHearingNotes: {} + } + }, + appeals: { + 'adfd7d18-f848-4df5-9df2-9ca43c58dd13': { + id: 1647, + externalAppealId: 'adfd7d18-f848-4df5-9df2-9ca43c58dd13' + }, + } + }, + ...uiData, +}; /* eslint-enable max-lines */ From 6a7f753dcc1e50d58cb49792ec7dd6e0cced10c0 Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Tue, 25 Jul 2023 16:42:41 -0400 Subject: [PATCH 07/87] APPEALS-24996 update name of efolderurlfield --- client/app/queue/components/EfolderUrlField.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/app/queue/components/EfolderUrlField.jsx b/client/app/queue/components/EfolderUrlField.jsx index c93f2a72158..1414b125729 100644 --- a/client/app/queue/components/EfolderUrlField.jsx +++ b/client/app/queue/components/EfolderUrlField.jsx @@ -21,7 +21,7 @@ const EfolderUrlField = (props) => { return <> Date: Tue, 25 Jul 2023 17:42:52 -0400 Subject: [PATCH 08/87] APPEALS-24996 import initialState for code climate issue --- .../queue/taskActionModals/taskActionModalData.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/client/test/data/queue/taskActionModals/taskActionModalData.js b/client/test/data/queue/taskActionModals/taskActionModalData.js index da0be24d2e2..8727031c85e 100644 --- a/client/test/data/queue/taskActionModals/taskActionModalData.js +++ b/client/test/data/queue/taskActionModals/taskActionModalData.js @@ -1,5 +1,6 @@ /* eslint-disable max-lines */ import COPY from '../../../../COPY'; +import { initialState } from '../../../../app/reader/CaseSelect/CaseSelectReducer'; export const uiData = { ui: { highlightFormItems: false, @@ -1802,19 +1803,7 @@ export const rootTaskData = { fetchedAllCasesFor: {} }, caseSelect: { - selectedAppealVacolsId: null, - isRequestingAppealsUsingVeteranId: false, - selectedAppeal: {}, - receivedAppeals: [], - search: { - showErrorMessage: false, - noAppealsFoundSearchQueryValue: null - }, - caseSelectCriteria: { - searchQuery: '' - }, - assignments: [], - assignmentsLoaded: false + initialState }, queue: { judges: {}, From 8ccfbe6f5f3094e3b136af7f489c8a6af21b5ccc Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Wed, 26 Jul 2023 09:57:22 -0400 Subject: [PATCH 09/87] APPEALS-24997 created CompleteHearingPostponementRequestModal file --- ...ompleteHearingPostponementRequestModal.jsx | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx new file mode 100644 index 00000000000..9e66b748b49 --- /dev/null +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -0,0 +1,23 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import QueueFlowModal from '../QueueFlowModal'; + +const CompleteHearingPostponementRequestModal = (props) => { + const validateForm = () => false; + + const submit = () => console.log(props); + + return ( + + ); +}; + +export default CompleteHearingPostponementRequestModal; From cc93ae1ebad95cddf5e29d1abd94cace8228fa0f Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Wed, 26 Jul 2023 11:24:12 -0400 Subject: [PATCH 10/87] APPEALS-24997 Created modal and completed base level granted/denied radio --- client/COPY.json | 1 + client/app/queue/QueueApp.jsx | 15 ++++++- ...ompleteHearingPostponementRequestModal.jsx | 41 +++++++++++++++++-- client/app/queue/constants.js | 5 ++- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/client/COPY.json b/client/COPY.json index 418b2b4433d..65c92e244bd 100644 --- a/client/COPY.json +++ b/client/COPY.json @@ -803,6 +803,7 @@ "APPEAL_WITHDRAWAL_MAIL_TASK_LABEL": "Withdrawal of appeal", "CAVC_CORRESPONDENCE_MAIL_TASK_LABEL": "CAVC Correspondence", "CLEAR_AND_UNMISTAKABLE_ERROR_MAIL_TASK_LABEL": "CUE-related", + "COMPLETE_HEARING_POSTPONEMENT_REQUEST": "What is the Judge’s ruling on the motion to postpone?", "CONGRESSIONAL_INTEREST_MAIL_TASK_LABEL": "Congressional interest", "CONTROLLED_CORRESPONDENCE_MAIL_TASK_LABEL": "Controlled correspondence", "DEATH_CERTIFICATE_MAIL_TASK_LABEL": "Death certificate", diff --git a/client/app/queue/QueueApp.jsx b/client/app/queue/QueueApp.jsx index f1b6d83a52c..c30a9fea620 100644 --- a/client/app/queue/QueueApp.jsx +++ b/client/app/queue/QueueApp.jsx @@ -67,7 +67,8 @@ import SetOvertimeStatusModal from './SetOvertimeStatusModal'; import StartHoldModal from './components/StartHoldModal'; import EndHoldModal from './components/EndHoldModal'; import BulkAssignModal from './components/BulkAssignModal'; - +import CompleteHearingPostponementRequestModal + from './components/hearingMailRequestModals/CompleteHearingPostponementRequestModal'; import CaseListView from './CaseListView'; import CaseDetailsView from './CaseDetailsView'; import SubmitDecisionView from './SubmitDecisionView'; @@ -652,6 +653,10 @@ class QueueApp extends React.PureComponent { ); + routedCompleteHearingPostponementRequest = (props) => ( + + ); + queueName = () => this.props.userRole === USER_ROLE_TYPES.attorney ? 'Your Queue' : @@ -1199,6 +1204,12 @@ class QueueApp extends React.PureComponent { title={`${PAGE_TITLES.RETURN_TO_BOARD_INTAKE} | Caseflow`} render={this.routedVhaCaregiverSupportReturnToBoardIntake} /> + { + const formReducer = (state, action) => { + switch (action.type) { + case 'granted': + return { + ...state, + granted: action.payload + }; + default: + throw new Error("Unknown action type"); + } + }; + + const [state, dispatch] = useReducer( + formReducer, + { + granted: null, + } + ); + const validateForm = () => false; const submit = () => console.log(props); + console.log(state); + return ( { validateForm={validateForm} submit={submit} pathAfterSubmit="/organizations/hearing-admin" - /> + > + dispatch({ type: 'granted', payload: value === 'true' })} + value={state.granted} + options={[ + { displayText: 'Granted', value: true }, + { displayText: 'Denied', value: false } + ]} + /> + ); }; diff --git a/client/app/queue/constants.js b/client/app/queue/constants.js index f02c465abb3..e139e897cfa 100644 --- a/client/app/queue/constants.js +++ b/client/app/queue/constants.js @@ -210,8 +210,9 @@ export const PAGE_TITLES = { CHANGE_TASK_TYPE: 'Change Task Type', CONVERT_HEARING_TO_VIRTUAL: 'Change Hearing Request Type to Virtual', CONVERT_HEARING_TO_VIDEO: 'Change Hearing Request Type to Video', - CONVERT_HEARING_TO_CENTRAL: 'Change Hearing Request Type to Central' - + CONVERT_HEARING_TO_CENTRAL: 'Change Hearing Request Type to Central', + // Confirm with UX title for HPR + COMPLETE_HEARING_POSTPONEMENT_REQUEST: 'Complete Heaering Postponement Request' }; export const CUSTOM_HOLD_DURATION_TEXT = 'Custom'; From a6896e794be7525ae2eb048518a3238705c4eb7f Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Wed, 26 Jul 2023 12:02:45 -0400 Subject: [PATCH 11/87] APPEALS-24997 Completed alert functionality and toyed with styling... --- client/COPY.json | 5 +++- client/app/components/Alert.jsx | 2 ++ ...ompleteHearingPostponementRequestModal.jsx | 30 ++++++++++++------- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/client/COPY.json b/client/COPY.json index 65c92e244bd..e2617ab3774 100644 --- a/client/COPY.json +++ b/client/COPY.json @@ -803,7 +803,10 @@ "APPEAL_WITHDRAWAL_MAIL_TASK_LABEL": "Withdrawal of appeal", "CAVC_CORRESPONDENCE_MAIL_TASK_LABEL": "CAVC Correspondence", "CLEAR_AND_UNMISTAKABLE_ERROR_MAIL_TASK_LABEL": "CUE-related", - "COMPLETE_HEARING_POSTPONEMENT_REQUEST": "What is the Judge’s ruling on the motion to postpone?", + "COMPLETE_HEARING_POSTPONEMENT_REQUEST": { + "RADIO_LABEL": "What is the Judge’s ruling on the motion to postpone?", + "ALERT": "By marking this task as complete, you will postpone the hearing" + }, "CONGRESSIONAL_INTEREST_MAIL_TASK_LABEL": "Congressional interest", "CONTROLLED_CORRESPONDENCE_MAIL_TASK_LABEL": "Controlled correspondence", "DEATH_CERTIFICATE_MAIL_TASK_LABEL": "Death certificate", diff --git a/client/app/components/Alert.jsx b/client/app/components/Alert.jsx index 2d851edb3a8..1856b0c93c1 100644 --- a/client/app/components/Alert.jsx +++ b/client/app/components/Alert.jsx @@ -25,6 +25,8 @@ export default class Alert extends React.Component { 'usa-alert-slim': !title, fixed, 'cf-margin-bottom-2rem': lowerMargin, + // TODO:There was note in Prototype Branch to fix margin top. Confirm desired changes + 'cf-margin-top-0rem': lowerMargin, }); return ( diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index 9cdfca94273..795266a6106 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -1,20 +1,21 @@ import React, { useReducer } from 'react'; -// import PropTypes from 'prop-types'; +import PropTypes from 'prop-types'; import COPY from '../../../../COPY'; import QueueFlowModal from '../QueueFlowModal'; import RadioField from '../../../components/RadioField'; +import Alert from '../../../components/Alert'; const CompleteHearingPostponementRequestModal = (props) => { const formReducer = (state, action) => { switch (action.type) { - case 'granted': - return { - ...state, - granted: action.payload - }; - default: - throw new Error("Unknown action type"); + case 'granted': + return { + ...state, + granted: action.payload + }; + default: + throw new Error('Unknown action type'); } }; @@ -29,8 +30,6 @@ const CompleteHearingPostponementRequestModal = (props) => { const submit = () => console.log(props); - console.log(state); - return ( { > dispatch({ type: 'granted', payload: value === 'true' })} value={state.granted} @@ -51,8 +50,17 @@ const CompleteHearingPostponementRequestModal = (props) => { { displayText: 'Denied', value: false } ]} /> + {state.granted && } ); }; +CompleteHearingPostponementRequestModal.propTypes = { + register: PropTypes.func +}; + export default CompleteHearingPostponementRequestModal; From ef3ae72fbbe1d6097e066cb709928b065ac2f598 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Wed, 26 Jul 2023 13:22:38 -0400 Subject: [PATCH 12/87] APPEALS-24997 completed date selector --- client/COPY.json | 4 ---- ...ompleteHearingPostponementRequestModal.jsx | 22 +++++++++++++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/client/COPY.json b/client/COPY.json index e2617ab3774..418b2b4433d 100644 --- a/client/COPY.json +++ b/client/COPY.json @@ -803,10 +803,6 @@ "APPEAL_WITHDRAWAL_MAIL_TASK_LABEL": "Withdrawal of appeal", "CAVC_CORRESPONDENCE_MAIL_TASK_LABEL": "CAVC Correspondence", "CLEAR_AND_UNMISTAKABLE_ERROR_MAIL_TASK_LABEL": "CUE-related", - "COMPLETE_HEARING_POSTPONEMENT_REQUEST": { - "RADIO_LABEL": "What is the Judge’s ruling on the motion to postpone?", - "ALERT": "By marking this task as complete, you will postpone the hearing" - }, "CONGRESSIONAL_INTEREST_MAIL_TASK_LABEL": "Congressional interest", "CONTROLLED_CORRESPONDENCE_MAIL_TASK_LABEL": "Controlled correspondence", "DEATH_CERTIFICATE_MAIL_TASK_LABEL": "Death certificate", diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index 795266a6106..99b3d47a688 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -5,6 +5,7 @@ import COPY from '../../../../COPY'; import QueueFlowModal from '../QueueFlowModal'; import RadioField from '../../../components/RadioField'; import Alert from '../../../components/Alert'; +import DateSelector from '../../../components/DateSelector'; const CompleteHearingPostponementRequestModal = (props) => { const formReducer = (state, action) => { @@ -14,6 +15,11 @@ const CompleteHearingPostponementRequestModal = (props) => { ...state, granted: action.payload }; + case 'rulingDate': + return { + ...state, + date: action.payload + } default: throw new Error('Unknown action type'); } @@ -23,6 +29,7 @@ const CompleteHearingPostponementRequestModal = (props) => { formReducer, { granted: null, + date: null } ); @@ -39,9 +46,10 @@ const CompleteHearingPostponementRequestModal = (props) => { submit={submit} pathAfterSubmit="/organizations/hearing-admin" > + dispatch({ type: 'granted', payload: value === 'true' })} value={state.granted} @@ -50,11 +58,21 @@ const CompleteHearingPostponementRequestModal = (props) => { { displayText: 'Denied', value: false } ]} /> + {state.granted && } + + dispatch({ type: 'rulingDate', payload: value })} + value={state.date} + type="date" + noFutureDates + /> ); }; From ccd944ed5e8194b9617251b6fbb2c6a96dd48a59 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Wed, 26 Jul 2023 13:57:51 -0400 Subject: [PATCH 13/87] APPEALS-24997 Created schedule option radio --- client/app/components/Alert.jsx | 5 +- ...ompleteHearingPostponementRequestModal.jsx | 46 ++++++++++++++++--- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/client/app/components/Alert.jsx b/client/app/components/Alert.jsx index 1856b0c93c1..8c879d19d39 100644 --- a/client/app/components/Alert.jsx +++ b/client/app/components/Alert.jsx @@ -17,7 +17,7 @@ export default class Alert extends React.Component { } render() { - const { fixed, title, type, styling, lowerMargin } = this.props; + const { fixed, title, type, styling, lowerMargin, lowerMarginTop } = this.props; const typeClass = `usa-alert-${type}`; @@ -26,7 +26,7 @@ export default class Alert extends React.Component { fixed, 'cf-margin-bottom-2rem': lowerMargin, // TODO:There was note in Prototype Branch to fix margin top. Confirm desired changes - 'cf-margin-top-0rem': lowerMargin, + 'cf-margin-top-0rem': lowerMarginTop, }); return ( @@ -57,6 +57,7 @@ Alert.propTypes = { * Sets `.cf-margin-bottom-2rem` class */ lowerMargin: PropTypes.bool, + lowerMarginTop: PropTypes.bool, message: PropTypes.node, /** diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index 99b3d47a688..c9aeaa494ad 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -1,11 +1,11 @@ import React, { useReducer } from 'react'; import PropTypes from 'prop-types'; -import COPY from '../../../../COPY'; import QueueFlowModal from '../QueueFlowModal'; import RadioField from '../../../components/RadioField'; import Alert from '../../../components/Alert'; import DateSelector from '../../../components/DateSelector'; +import TextareaField from '../../../components/TextareaField'; const CompleteHearingPostponementRequestModal = (props) => { const formReducer = (state, action) => { @@ -19,7 +19,12 @@ const CompleteHearingPostponementRequestModal = (props) => { return { ...state, date: action.payload - } + }; + case 'instructions': + return { + ...state, + instructions: action.payload + }; default: throw new Error('Unknown action type'); } @@ -29,7 +34,8 @@ const CompleteHearingPostponementRequestModal = (props) => { formReducer, { granted: null, - date: null + date: null, + instructions: null } ); @@ -37,6 +43,16 @@ const CompleteHearingPostponementRequestModal = (props) => { const submit = () => console.log(props); + const GRANTED_OR_DENIED_OPTIONS = [ + { displayText: 'Granted', value: true }, + { displayText: 'Denied', value: false } + ]; + + const RESCHEDULE_HEARING_OPTIONS = [ + { displayText: 'Reschedule immediately', value: 'schedule_now' }, + { displayText: 'Send to Schedule Veteran list', value: 'schedule_later' } + ]; + return ( { dispatch({ type: 'granted', payload: value === 'true' })} value={state.granted} - options={[ - { displayText: 'Granted', value: true }, - { displayText: 'Denied', value: false } - ]} + options={GRANTED_OR_DENIED_OPTIONS} /> {state.granted && } { type="date" noFutureDates /> + + {state.granted && } + + dispatch({ type: 'instructions', payload: value })} + + /> ); }; From 0d5c82fffcc146c4e46be9316cd6f41c410adc24 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Wed, 26 Jul 2023 14:27:33 -0400 Subject: [PATCH 14/87] APPEALS-24997 adjusted margins --- client/app/components/Alert.jsx | 4 +- client/app/components/DateSelector.jsx | 3 + ...ompleteHearingPostponementRequestModal.jsx | 90 ++++++++++--------- 3 files changed, 51 insertions(+), 46 deletions(-) diff --git a/client/app/components/Alert.jsx b/client/app/components/Alert.jsx index 8c879d19d39..af38296d9ad 100644 --- a/client/app/components/Alert.jsx +++ b/client/app/components/Alert.jsx @@ -17,7 +17,7 @@ export default class Alert extends React.Component { } render() { - const { fixed, title, type, styling, lowerMargin, lowerMarginTop } = this.props; + const { fixed, title, type, styling, lowerMargin } = this.props; const typeClass = `usa-alert-${type}`; @@ -25,8 +25,6 @@ export default class Alert extends React.Component { 'usa-alert-slim': !title, fixed, 'cf-margin-bottom-2rem': lowerMargin, - // TODO:There was note in Prototype Branch to fix margin top. Confirm desired changes - 'cf-margin-top-0rem': lowerMarginTop, }); return ( diff --git a/client/app/components/DateSelector.jsx b/client/app/components/DateSelector.jsx index 368e753cc4c..ca8b4095487 100644 --- a/client/app/components/DateSelector.jsx +++ b/client/app/components/DateSelector.jsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import TextField from '../components/TextField'; import ValidatorsUtil from '../util/ValidatorsUtil'; import COPY from '../../COPY'; +import { marginBottom } from '../queue/constants'; const DEFAULT_TEXT = 'mm/dd/yyyy'; @@ -21,6 +22,7 @@ export const DateSelector = (props) => { value, dateErrorMessage, noFutureDates = false, + inputStyling, ...passthroughProps } = props; @@ -64,6 +66,7 @@ export const DateSelector = (props) => { {...passthroughProps} max={max} dateErrorMessage={dateErrorMessage} + inputStyling={inputStyling} /> ); }; diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index c9aeaa494ad..fe68f46d0b9 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -7,6 +7,8 @@ import Alert from '../../../components/Alert'; import DateSelector from '../../../components/DateSelector'; import TextareaField from '../../../components/TextareaField'; +import { marginTop, marginBottom } from '../../constants'; + const CompleteHearingPostponementRequestModal = (props) => { const formReducer = (state, action) => { switch (action.type) { @@ -62,49 +64,51 @@ const CompleteHearingPostponementRequestModal = (props) => { submit={submit} pathAfterSubmit="/organizations/hearing-admin" > - - dispatch({ type: 'granted', payload: value === 'true' })} - value={state.granted} - options={GRANTED_OR_DENIED_OPTIONS} - /> - - {state.granted && } - - dispatch({ type: 'rulingDate', payload: value })} - value={state.date} - type="date" - noFutureDates - /> - - {state.granted && } - - dispatch({ type: 'instructions', payload: value })} - - /> + <> + dispatch({ type: 'granted', payload: value === 'true' })} + value={state.granted} + options={GRANTED_OR_DENIED_OPTIONS} + /> + + {state.granted && } + + dispatch({ type: 'rulingDate', payload: value })} + value={state.date} + type="date" + noFutureDates + inputStyling={marginBottom(0)} + /> + + {state.granted && } + + dispatch({ type: 'instructions', payload: value })} + /> + ); }; From 9d78fe0cd7174d4eb222075ec644a63cbd8d60cd Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Wed, 26 Jul 2023 15:20:02 -0400 Subject: [PATCH 15/87] APPEALS-24996 Update styling and formatting of instructions --- client/app/queue/CreateMailTaskDialog.jsx | 11 ++++++++--- client/app/queue/components/TaskRows.jsx | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/client/app/queue/CreateMailTaskDialog.jsx b/client/app/queue/CreateMailTaskDialog.jsx index 0a5d48a9641..f7df4e6fb9b 100644 --- a/client/app/queue/CreateMailTaskDialog.jsx +++ b/client/app/queue/CreateMailTaskDialog.jsx @@ -49,9 +49,14 @@ export class CreateMailTaskDialog extends React.Component { return instructionsAndValue(); } - prependUrlToInstructions = () => ( - this.isHearingRequestMailTask() ? (`${this.state.eFolderUrl} - ${this.state.instructions}`) : this.state.instructions - ); + prependUrlToInstructions = () => { + + if (this.isHearingRequestMailTask()) { + return (`**LINK TO DOCUMENT:** \n ${this.state.eFolderUrl} \n **DETAILS:** \n ${this.state.instructions}`); + } + + return this.state.instructions; + }; submit = () => { const { appeal, task } = this.props; diff --git a/client/app/queue/components/TaskRows.jsx b/client/app/queue/components/TaskRows.jsx index 423aef3772b..15f35e6f27e 100644 --- a/client/app/queue/components/TaskRows.jsx +++ b/client/app/queue/components/TaskRows.jsx @@ -306,7 +306,7 @@ class TaskRows extends React.PureComponent { // We specify the same 2.4rem margin-bottom as paragraphs to each set of instructions // to ensure a consistent margin between instruction content and the "Hide" button - const divStyles = { marginBottom: '2.4rem' }; + const divStyles = { marginBottom: '2.4rem', marginTop: '1em' }; return ( From c1e11e3c077b6857da1b25165107390019cbf804 Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Wed, 26 Jul 2023 15:30:29 -0400 Subject: [PATCH 16/87] APPEALS-24996 Adjusted font size of bold text --- client/app/styles/queue/_timeline.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/app/styles/queue/_timeline.scss b/client/app/styles/queue/_timeline.scss index 194bafda198..34da8acebf7 100644 --- a/client/app/styles/queue/_timeline.scss +++ b/client/app/styles/queue/_timeline.scss @@ -95,4 +95,8 @@ .task-instructions > p { margin-top: 0; + + strong { + font-size: 15px; + } } From a3877448039b55c01776505c6392d9fa3f5d2b5b Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Thu, 27 Jul 2023 09:48:46 -0400 Subject: [PATCH 17/87] APPEALS-24996 Code review suggested changes --- client/app/queue/CreateMailTaskDialog.jsx | 1 + client/app/queue/components/EfolderUrlField.jsx | 2 +- client/app/styles/_commons.scss | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/client/app/queue/CreateMailTaskDialog.jsx b/client/app/queue/CreateMailTaskDialog.jsx index f7df4e6fb9b..5260cfce5b9 100644 --- a/client/app/queue/CreateMailTaskDialog.jsx +++ b/client/app/queue/CreateMailTaskDialog.jsx @@ -115,6 +115,7 @@ export class CreateMailTaskDialog extends React.Component { title={COPY.CREATE_MAIL_TASK_TITLE} pathAfterSubmit={`/queue/appeals/${this.props.appealId}`} submitDisabled={!this.validateForm()} + submitButtonClassNames={['usa-button']} > { return <> Date: Thu, 27 Jul 2023 11:23:43 -0400 Subject: [PATCH 18/87] APPEALS-24996 Removed unused imports, adjusted label text in expect statement --- .../app/queue/components/CreateMailTaskDialog.test.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/client/test/app/queue/components/CreateMailTaskDialog.test.js b/client/test/app/queue/components/CreateMailTaskDialog.test.js index 6548e41978f..2ee59425e09 100644 --- a/client/test/app/queue/components/CreateMailTaskDialog.test.js +++ b/client/test/app/queue/components/CreateMailTaskDialog.test.js @@ -4,16 +4,11 @@ import { render, screen } from '@testing-library/react'; import { Provider } from 'react-redux'; import { applyMiddleware, createStore, compose } from 'redux'; import thunk from 'redux-thunk'; -import COPY from '../../../../COPY'; import CreateMailTaskDialog from '../../../../app/queue/CreateMailTaskDialog'; import { createQueueReducer, getAppealId, - getTaskId, - enterTextFieldOptions, - enterModalRadioOptions, - selectFromDropdown, - clickSubmissionButton + getTaskId } from './modalUtils'; import { rootTaskData } from '../../../data/queue/taskActionModals/taskActionModalData'; import userEvent from '@testing-library/user-event'; @@ -66,7 +61,7 @@ describe('CreateMailTaskDialog', () => { userEvent.type(screen.getByRole('combobox'), 'Hearing postponement request{enter}'); - expect(screen.getByLabelText('Include Caseflow Reader document hyperlink to request hearing postponement')). + expect(screen.getByLabelText('Include Caseflow Reader document hyperlink to request a hearing postponement')). toBeTruthy(); }); From 082bdf3290774e57e0452400066f2055eca77041 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Thu, 27 Jul 2023 14:25:12 -0400 Subject: [PATCH 19/87] APPEALS-24997 fixed scheduledFor controlled input --- client/app/components/DateSelector.jsx | 7 +++-- ...ompleteHearingPostponementRequestModal.jsx | 27 +++++++++++++++---- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/client/app/components/DateSelector.jsx b/client/app/components/DateSelector.jsx index ca8b4095487..6883cb5471e 100644 --- a/client/app/components/DateSelector.jsx +++ b/client/app/components/DateSelector.jsx @@ -3,7 +3,6 @@ import PropTypes from 'prop-types'; import TextField from '../components/TextField'; import ValidatorsUtil from '../util/ValidatorsUtil'; import COPY from '../../COPY'; -import { marginBottom } from '../queue/constants'; const DEFAULT_TEXT = 'mm/dd/yyyy'; @@ -60,7 +59,7 @@ export const DateSelector = (props) => { type={type} value={value} validationError={dateValidationError(value)} - onChange={onChange} + onChange={(value) => console.log(value)} placeholder={DEFAULT_TEXT} required={required} {...passthroughProps} @@ -77,7 +76,7 @@ DateSelector.propTypes = { * The initial value of the `input` element; use for uncontrolled components where not using `value` prop */ defaultValue: PropTypes.string, - + inputStyling: PropTypes.object, dateErrorMessage: PropTypes.string, /** @@ -136,7 +135,7 @@ DateSelector.propTypes = { /** * The value of the `input` element; required for a controlled component */ - value: PropTypes.string, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), /** * Disables future dates from being selected or entered diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index fe68f46d0b9..322ba08d314 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -15,7 +15,8 @@ const CompleteHearingPostponementRequestModal = (props) => { case 'granted': return { ...state, - granted: action.payload + granted: action.payload, + scheduledOption: null }; case 'rulingDate': return { @@ -27,6 +28,11 @@ const CompleteHearingPostponementRequestModal = (props) => { ...state, instructions: action.payload }; + case 'scheduledOption': + return { + ...state, + scheduledOption: action.payload + } default: throw new Error('Unknown action type'); } @@ -36,12 +42,21 @@ const CompleteHearingPostponementRequestModal = (props) => { formReducer, { granted: null, - date: null, - instructions: null + date: '', + instructions: '', + scheduledOption: null } ); - const validateForm = () => false; + const validateForm = () => { + const { granted, date, instructions, scheduledOption } = state; + + if (granted) { + return date !== '' && instructions !== '' && scheduledOption !== ''; + } + + return granted !== null && date !== '' && instructions !== ''; + }; const submit = () => console.log(props); @@ -59,7 +74,7 @@ const CompleteHearingPostponementRequestModal = (props) => { { name="schedulOptionField" label="How would you like to proceed?:" inputRef={props.register} + onChange={(value) => dispatch({ type: 'scheduledOption', payload: value })} + value={state.scheduledOption} options={RESCHEDULE_HEARING_OPTIONS} vertical styling={marginBottom(1)} From 8dc91fb5024b4ddc0f83ff6361e9333162e6e4a6 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Thu, 27 Jul 2023 15:26:27 -0400 Subject: [PATCH 20/87] APPEALS-24997 Added date validation to prevent form submission --- client/app/components/DateSelector.jsx | 2 +- client/app/components/RadioField.jsx | 2 +- .../CompleteHearingPostponementRequestModal.jsx | 10 +++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/client/app/components/DateSelector.jsx b/client/app/components/DateSelector.jsx index 6883cb5471e..50a99a87f31 100644 --- a/client/app/components/DateSelector.jsx +++ b/client/app/components/DateSelector.jsx @@ -59,7 +59,7 @@ export const DateSelector = (props) => { type={type} value={value} validationError={dateValidationError(value)} - onChange={(value) => console.log(value)} + onChange={onChange} placeholder={DEFAULT_TEXT} required={required} {...passthroughProps} diff --git a/client/app/components/RadioField.jsx b/client/app/components/RadioField.jsx index f566bcbb30a..203f83e9342 100644 --- a/client/app/components/RadioField.jsx +++ b/client/app/components/RadioField.jsx @@ -204,7 +204,7 @@ RadioField.propTypes = { /** * The value of the named `input` element(s); required for a controlled component */ - value: PropTypes.string, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), /** * Stack `input` elements vertically (automatic for more than two options) diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index 322ba08d314..a972f2c49bf 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -1,5 +1,6 @@ import React, { useReducer } from 'react'; import PropTypes from 'prop-types'; +import ValidatorsUtil from '../../../util/ValidatorsUtil'; import QueueFlowModal from '../QueueFlowModal'; import RadioField from '../../../components/RadioField'; @@ -10,6 +11,8 @@ import TextareaField from '../../../components/TextareaField'; import { marginTop, marginBottom } from '../../constants'; const CompleteHearingPostponementRequestModal = (props) => { + const { futureDate } = ValidatorsUtil; + const formReducer = (state, action) => { switch (action.type) { case 'granted': @@ -48,14 +51,16 @@ const CompleteHearingPostponementRequestModal = (props) => { } ); + const validateDate = (date) => date !== '' && !futureDate(date); + const validateForm = () => { const { granted, date, instructions, scheduledOption } = state; if (granted) { - return date !== '' && instructions !== '' && scheduledOption !== ''; + return validateDate(date) && instructions !== '' && scheduledOption !== ''; } - return granted !== null && date !== '' && instructions !== ''; + return granted !== null && validateDate(date) && instructions !== ''; }; const submit = () => console.log(props); @@ -104,7 +109,6 @@ const CompleteHearingPostponementRequestModal = (props) => { value={state.date} type="date" noFutureDates - inputStyling={marginBottom(0)} /> {state.granted && Date: Sun, 30 Jul 2023 10:55:24 -0400 Subject: [PATCH 21/87] APPEALS-24997 improved validation to include incorrect dates --- client/app/components/DateSelector.jsx | 16 ++++++- ...ompleteHearingPostponementRequestModal.jsx | 47 ++++++++++--------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/client/app/components/DateSelector.jsx b/client/app/components/DateSelector.jsx index 50a99a87f31..6d9d138e8a4 100644 --- a/client/app/components/DateSelector.jsx +++ b/client/app/components/DateSelector.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import TextField from '../components/TextField'; import ValidatorsUtil from '../util/ValidatorsUtil'; @@ -22,6 +22,7 @@ export const DateSelector = (props) => { dateErrorMessage, noFutureDates = false, inputStyling, + validateDate, ...passthroughProps } = props; @@ -43,6 +44,12 @@ export const DateSelector = (props) => { return null; }; + useEffect(() => { + const dateIsValid = dateValidationError(value) === null && value !== ''; + + validateDate?.(dateIsValid); + }, [value]); + let max = '9999-12-31'; if (noFutureDates) { @@ -140,7 +147,12 @@ DateSelector.propTypes = { /** * Disables future dates from being selected or entered */ - noFutureDates: PropTypes.bool + noFutureDates: PropTypes.bool, + + /** + * Disables form submission if date is empty or invalid + */ + validateDate: PropTypes.func }; export default DateSelector; diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index a972f2c49bf..91cf02c12b6 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -1,6 +1,5 @@ import React, { useReducer } from 'react'; import PropTypes from 'prop-types'; -import ValidatorsUtil from '../../../util/ValidatorsUtil'; import QueueFlowModal from '../QueueFlowModal'; import RadioField from '../../../components/RadioField'; @@ -10,9 +9,17 @@ import TextareaField from '../../../components/TextareaField'; import { marginTop, marginBottom } from '../../constants'; -const CompleteHearingPostponementRequestModal = (props) => { - const { futureDate } = ValidatorsUtil; +const RULING_OPTIONS = [ + { displayText: 'Granted', value: true }, + { displayText: 'Denied', value: false } +]; + +const POSTPONEMENT_ACTIONS = [ + { displayText: 'Reschedule immediately', value: 'reschedule' }, + { displayText: 'Send to Schedule Veteran list', value: 'schedule_later' } +]; +const CompleteHearingPostponementRequestModal = (props) => { const formReducer = (state, action) => { switch (action.type) { case 'granted': @@ -24,7 +31,12 @@ const CompleteHearingPostponementRequestModal = (props) => { case 'rulingDate': return { ...state, - date: action.payload + rulingDate: { ...state.rulingDate, value: action.payload } + }; + case 'dateIsValid': + return { + ...state, + rulingDate: { ...state.rulingDate, valid: action.payload } }; case 'instructions': return { @@ -45,36 +57,24 @@ const CompleteHearingPostponementRequestModal = (props) => { formReducer, { granted: null, - date: '', + rulingDate: { value: '', valid: false }, instructions: '', scheduledOption: null } ); - const validateDate = (date) => date !== '' && !futureDate(date); - const validateForm = () => { - const { granted, date, instructions, scheduledOption } = state; + const { granted, rulingDate, instructions, scheduledOption } = state; if (granted) { - return validateDate(date) && instructions !== '' && scheduledOption !== ''; + return rulingDate.valid && instructions !== '' && scheduledOption !== ''; } - return granted !== null && validateDate(date) && instructions !== ''; + return granted !== null && rulingDate.valid && instructions !== ''; }; const submit = () => console.log(props); - const GRANTED_OR_DENIED_OPTIONS = [ - { displayText: 'Granted', value: true }, - { displayText: 'Denied', value: false } - ]; - - const RESCHEDULE_HEARING_OPTIONS = [ - { displayText: 'Reschedule immediately', value: 'schedule_now' }, - { displayText: 'Send to Schedule Veteran list', value: 'schedule_later' } - ]; - return ( { inputRef={props.register} onChange={(value) => dispatch({ type: 'granted', payload: value === 'true' })} value={state.granted} - options={GRANTED_OR_DENIED_OPTIONS} + options={RULING_OPTIONS} /> {state.granted && { label="Date of ruling:" name="rulingDateSelector" onChange={(value) => dispatch({ type: 'rulingDate', payload: value })} - value={state.date} + value={state.rulingDate.value} type="date" noFutureDates + validateDate={(value) => dispatch({ type: 'dateIsValid', payload: value })} /> {state.granted && { inputRef={props.register} onChange={(value) => dispatch({ type: 'scheduledOption', payload: value })} value={state.scheduledOption} - options={RESCHEDULE_HEARING_OPTIONS} + options={POSTPONEMENT_ACTIONS} vertical styling={marginBottom(1)} />} From bcb5e801fca02f41a17dee415a332d33e7d45d1e Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Sun, 30 Jul 2023 10:58:18 -0400 Subject: [PATCH 22/87] APPEALS-24997 refactored useEffect on DateSelector --- client/app/components/DateSelector.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/app/components/DateSelector.jsx b/client/app/components/DateSelector.jsx index 6d9d138e8a4..62c3c595474 100644 --- a/client/app/components/DateSelector.jsx +++ b/client/app/components/DateSelector.jsx @@ -45,9 +45,11 @@ export const DateSelector = (props) => { }; useEffect(() => { - const dateIsValid = dateValidationError(value) === null && value !== ''; + if (validateDate) { + const dateIsValid = dateValidationError(value) === null && value !== ''; - validateDate?.(dateIsValid); + validateDate(dateIsValid); + } }, [value]); let max = '9999-12-31'; From a332659d43b881ac67d708e3890f9ac96eae556e Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Mon, 31 Jul 2023 09:45:05 -0400 Subject: [PATCH 23/87] APPEALS-24997 refactored constants --- .../CompleteHearingPostponementRequestModal.jsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index 91cf02c12b6..5e93577f77a 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -14,9 +14,14 @@ const RULING_OPTIONS = [ { displayText: 'Denied', value: false } ]; +const ACTIONS = { + RESCHEDULE: 'reschedule', + SCHEDULE_LATER: 'schedule_later' +}; + const POSTPONEMENT_ACTIONS = [ - { displayText: 'Reschedule immediately', value: 'reschedule' }, - { displayText: 'Send to Schedule Veteran list', value: 'schedule_later' } + { displayText: 'Reschedule immediately', value: ACTIONS.RESCHEDULE }, + { displayText: 'Send to Schedule Veteran list', value: ACTIONS.SCHEDULE_LATER } ]; const CompleteHearingPostponementRequestModal = (props) => { From dd562b70c5bd448787977afe33c8698f23efec5b Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Mon, 31 Jul 2023 10:47:10 -0400 Subject: [PATCH 24/87] APPEALS-24997 implemented useState to reduce date validation firing --- client/app/components/DateSelector.jsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/client/app/components/DateSelector.jsx b/client/app/components/DateSelector.jsx index 62c3c595474..aa39bcf46ae 100644 --- a/client/app/components/DateSelector.jsx +++ b/client/app/components/DateSelector.jsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import TextField from '../components/TextField'; import ValidatorsUtil from '../util/ValidatorsUtil'; @@ -7,6 +7,8 @@ import COPY from '../../COPY'; const DEFAULT_TEXT = 'mm/dd/yyyy'; export const DateSelector = (props) => { + const [dateError, setDateError] = useState(null); + const { dateValidator, futureDate } = ValidatorsUtil; const { @@ -44,6 +46,13 @@ export const DateSelector = (props) => { return null; }; + useEffect(() => { + const errorMsg = dateValidationError(value); + + setDateError(errorMsg); + validateDate?.(value !== '' && errorMsg === null); + }, [value]); + useEffect(() => { if (validateDate) { const dateIsValid = dateValidationError(value) === null && value !== ''; @@ -67,7 +76,7 @@ export const DateSelector = (props) => { readOnly={readOnly} type={type} value={value} - validationError={dateValidationError(value)} + validationError={dateError} onChange={onChange} placeholder={DEFAULT_TEXT} required={required} From 394fccb630a924c57524e07d34019d920e496425 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Mon, 31 Jul 2023 11:29:51 -0400 Subject: [PATCH 25/87] APPEALS-24997 played with styling --- .../CompleteHearingPostponementRequestModal.jsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index 5e93577f77a..e7797dc4eec 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -98,6 +98,7 @@ const CompleteHearingPostponementRequestModal = (props) => { onChange={(value) => dispatch({ type: 'granted', payload: value === 'true' })} value={state.granted} options={RULING_OPTIONS} + styling={marginBottom(1)} /> {state.granted && { type="date" noFutureDates validateDate={(value) => dispatch({ type: 'dateIsValid', payload: value })} + inputStyling={marginBottom(1)} /> {state.granted && { value={state.scheduledOption} options={POSTPONEMENT_ACTIONS} vertical - styling={marginBottom(1)} + styling={marginBottom(1.5)} />} { name="instructionsField" id="completePostponementInstructions" onChange={(value) => dispatch({ type: 'instructions', payload: value })} + styling={marginBottom(0)} /> From 4d87f8d0e101e70682a912aae3f6293ca4a281c0 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Mon, 31 Jul 2023 12:02:21 -0400 Subject: [PATCH 26/87] APPEALS-24997 refactored copy --- client/COPY.json | 3 ++- .../CompleteHearingPostponementRequestModal.jsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/client/COPY.json b/client/COPY.json index 418b2b4433d..29c03c8cf3b 100644 --- a/client/COPY.json +++ b/client/COPY.json @@ -1382,5 +1382,6 @@ "DATE_SELECTOR_INVALID_DATE_ERROR": "Please select a valid date", "VHA_ACTION_PLACE_CUSTOM_HOLD_COPY": "Enter a custom number of days for the hold (Value must be between 1 and 45 for VHA users)", "VHA_CANCEL_TASK_INSTRUCTIONS_LABEL": "Why are you returning? Provide any important context", - "DISPOSITION_DECISION_DATE_LABEL": "Thank you for completing your decision in Caseflow. Please indicate the decision date." + "DISPOSITION_DECISION_DATE_LABEL": "Thank you for completing your decision in Caseflow. Please indicate the decision date.", + "PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL": "Provide instructions and context for this action" } diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index e7797dc4eec..c3c6684660a 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -1,6 +1,7 @@ import React, { useReducer } from 'react'; import PropTypes from 'prop-types'; +import COPY from '../../../../COPY'; import QueueFlowModal from '../QueueFlowModal'; import RadioField from '../../../components/RadioField'; import Alert from '../../../components/Alert'; @@ -132,7 +133,7 @@ const CompleteHearingPostponementRequestModal = (props) => { />} dispatch({ type: 'instructions', payload: value })} From 6a8676f54214d00f9c4f25fd37ecce8dd1312553 Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Tue, 1 Aug 2023 12:55:31 -0400 Subject: [PATCH 27/87] APPEALS-25001 Removed constraint on AMA only --- app/models/tasks/root_task.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/tasks/root_task.rb b/app/models/tasks/root_task.rb index 4a06df49d8a..23dc40df819 100644 --- a/app/models/tasks/root_task.rb +++ b/app/models/tasks/root_task.rb @@ -77,7 +77,7 @@ def hide_from_task_snapshot end def available_actions(user) - return [Constants.TASK_ACTIONS.CREATE_MAIL_TASK.to_h] if RootTask.user_can_create_mail_task?(user) && ama? + return [Constants.TASK_ACTIONS.CREATE_MAIL_TASK.to_h] if RootTask.user_can_create_mail_task?(user) [] end From 6e85fa26ea197b0abf2d2166eb0c7b0a2ea73b7d Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Tue, 1 Aug 2023 14:06:35 -0400 Subject: [PATCH 28/87] APPEALS-25001 Reduced options for legacy appeals to only allow for new mail task --- app/models/tasks/mail_task.rb | 4 ++++ app/repositories/task_action_repository.rb | 9 +++++++-- app/workflows/tasks_for_appeal.rb | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/models/tasks/mail_task.rb b/app/models/tasks/mail_task.rb index a0879242381..4b2478f4340 100644 --- a/app/models/tasks/mail_task.rb +++ b/app/models/tasks/mail_task.rb @@ -20,6 +20,10 @@ class MailTask < Task def verify_org_task_unique; end prepend PrivacyActPending + LEGACY_MAIL_TASKS = [ + { label: "Hearing postponement request", value: "HearingPostponementRequestMailTask" } + ].freeze + class << self def blocking? # Some open mail tasks should block distribution of an appeal to judges. diff --git a/app/repositories/task_action_repository.rb b/app/repositories/task_action_repository.rb index 23c321fdb59..a0d565f77e3 100644 --- a/app/repositories/task_action_repository.rb +++ b/app/repositories/task_action_repository.rb @@ -18,8 +18,13 @@ def assign_to_organization_data(task, _user = nil) end def mail_assign_to_organization_data(task, user = nil) - options = MailTask.descendant_routing_options(user: user, appeal: task.appeal) - valid_options = task.appeal.outcoded? ? options : options.reject { |opt| opt[:value] == "VacateMotionMailTask" } + if task.appeal.is_a? Appeal + options = MailTask.descendant_routing_options(user: user, appeal: task.appeal) + valid_options = task.appeal.outcoded? ? options : options.reject { |opt| opt[:value] == "VacateMotionMailTask" } + elsif task.appeal.is_a? LegacyAppeal + valid_options = MailTask::LEGACY_MAIL_TASKS + end + { options: valid_options } end diff --git a/app/workflows/tasks_for_appeal.rb b/app/workflows/tasks_for_appeal.rb index dcd8719f592..13ff885dbfa 100644 --- a/app/workflows/tasks_for_appeal.rb +++ b/app/workflows/tasks_for_appeal.rb @@ -79,7 +79,7 @@ def initialize_hearing_tasks_for_travel_board? end def legacy_appeal_tasks - return [] unless user_is_judge_or_attorney? || user.can_act_on_behalf_of_judges? + # return [] unless user_is_judge_or_attorney? || user.can_act_on_behalf_of_judges? LegacyWorkQueue.tasks_by_appeal_id(appeal.vacols_id) end From ad116d565881d72ec5b8a6ee001575bc5b6a34f4 Mon Sep 17 00:00:00 2001 From: Minhazur Rahaman Date: Tue, 1 Aug 2023 14:16:57 -0400 Subject: [PATCH 29/87] APPEALS-25000 added feature test for hearing postponement request for changing task types --- spec/feature/queue/mail_task_spec.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/spec/feature/queue/mail_task_spec.rb b/spec/feature/queue/mail_task_spec.rb index 92780617d37..0b2b1ed41e9 100644 --- a/spec/feature/queue/mail_task_spec.rb +++ b/spec/feature/queue/mail_task_spec.rb @@ -144,4 +144,26 @@ expect(page).to have_content(new_instructions) end end + + describe "Hearing Postponement Request Mail Task" do + let(:distribution_task) { create(:distribution_task) } + let!(:schedule_hearing_task) do + ScheduleHearingTask.create( + appeal: distribution_task.appeal, + parent_id: distribution_task.id, + assigned_to: Bva.singleton + ) + end + let(:hpr_task) { create(:hearing_postponement_request_mail_task, :with_unscheduled_hearing) } + + it "change task type" do + HearingAdmin.singleton.add_user(User.current_user) + visit("queue/appeals/#{hpr_task.appeal.uuid}") + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: COPY::CHANGE_TASK_TYPE_SUBHEAD) + find(".cf-select__control", text: "Select an action type").click + find(".cf-select__option", text: "Change of address").click + fill_in(name: "Provide instructions and context for this change:", with: "instructions") + click_button("Change task type") + end + end end From a3b2a158631393d8594bfbd7dd7c736f9e510831 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Tue, 1 Aug 2023 17:09:39 -0400 Subject: [PATCH 30/87] APPEALS-24997 testing date selector --- client/test/app/jestSetup.js | 2 +- ...eteHearingPostponementRequestModal.test.js | 149 +++++ .../test/app/queue/components/modalUtils.js | 13 +- .../taskActionModals/taskActionModalData.js | 539 ++++++++++++++++++ 4 files changed, 701 insertions(+), 2 deletions(-) create mode 100644 client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js diff --git a/client/test/app/jestSetup.js b/client/test/app/jestSetup.js index e8fb9d3cc41..3a3e60f15ca 100644 --- a/client/test/app/jestSetup.js +++ b/client/test/app/jestSetup.js @@ -13,7 +13,7 @@ global.scrollTo = jest.fn(); // Spy to ignore console warnings jest.spyOn(console, 'warn').mockReturnValue(); -jest.spyOn(console, 'log').mockReturnValue(); +// jest.spyOn(console, 'log').mockReturnValue(); jest.spyOn(console, 'error').mockReturnValue(); // Mock the Date generated for all tests diff --git a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js new file mode 100644 index 00000000000..afdb7286fb6 --- /dev/null +++ b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js @@ -0,0 +1,149 @@ +import React from 'react'; +import { MemoryRouter, Route } from 'react-router'; +import { render, screen } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { applyMiddleware, createStore, compose } from 'redux'; +import thunk from 'redux-thunk' +import CompleteHearingPostponementRequestModal + from 'app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal'; +import { completeHearingPostponementRequestData } + from '../../../../data/queue/taskActionModals/taskActionModalData'; +import { + createQueueReducer, + getAppealId, + getTaskId, + enterModalRadioOptions, + enterInputValue +} from '../modalUtils'; +import COPY from '../../../../../COPY'; +import { add } from 'date-fns'; + +const renderCompleteHprModal = (storeValues) => { + const appealId = getAppealId(storeValues); + const taskId = getTaskId(storeValues, 'HearingPostponementRequestMailTask'); + const queueReducer = createQueueReducer(storeValues); + const store = createStore( + queueReducer, + compose(applyMiddleware(thunk)) + ); + + const path = `/queue/appeals/${appealId}/tasks/${taskId}/modal/complete_and_postpone`; + + return render( + + + { + return ; + }} path="/queue/appeals/:appealId/tasks/:taskId/modal/complete_and_postpone" /> + + + ); +}; + +describe('CompleteHearingPostponementRequestModal', () => { + const [granted, denied] = ['Granted', 'Denied']; + const datePrompt = 'Date of ruling:'; + const [reschedule, scheduleLater] = ['Reschedule immediately', 'Send to Schedule Veteran list']; + + const rescheduleBtn = () => screen.queryByRole('radio', { name: reschedule }); + const scheduleLaterBtn = () => screen.queryByRole('radio', { name: scheduleLater }); + + describe('on modal open', () => { + const modalAction = 'Mark as complete'; + + test('modal title: "Mark as complete"', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + expect(screen.getByRole('heading', { name: modalAction })).toBeInTheDocument(); + }); + + describe('judge ruling radio fields', () => { + const radioPrompt = 'What is the Judge’s ruling on the motion to postpone?'; + + test('have text prompt "What is the Judge’s ruling on the motion to postpone?"', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + expect(screen.getByText(radioPrompt)).toBeInTheDocument(); + }); + + test('have two options: "Granted" and "Denied"', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + expect(screen.getAllByRole('radio')).toHaveLength(2); + expect(screen.getByRole('radio', { name: granted })).toBeInTheDocument(); + expect(screen.getByRole('radio', { name: denied })).toBeInTheDocument(); + }); + }); + + describe('date selector', () => { + test('has date input with text prompt "Date of ruling:"', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + expect(screen.getByLabelText(datePrompt)).toBeInTheDocument(); + }); + }); + + describe('text area field', () => { + const instructions = `${COPY.PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL}:`; + + test('has text prompt "Provide instructions and context for this action:"', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + expect(screen.getByRole('textbox', { name: instructions })).toBeInTheDocument(); + }); + }); + + describe('schedule options radio fields', () => { + test('are not present', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + expect(rescheduleBtn()).not.toBeInTheDocument(); + expect(scheduleLaterBtn()).not.toBeInTheDocument(); + }); + }); + + describe('submit button', () => { + test('submit button is initially disabled', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + expect(screen.getByRole('button', { name: modalAction })).toBeDisabled(); + }); + }); + }); + + describe('on determine judge ruling', () => { + describe('radio option "Granted" is selected', () => { + test('radio fields with scheduling options are made visible', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + enterModalRadioOptions(granted); + expect(rescheduleBtn()).toBeInTheDocument(); + expect(scheduleLaterBtn()).toBeInTheDocument(); + }); + }); + + describe('radio option "Denied" is selected', () => { + test('radio fields with scheduling options are not visible', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + enterModalRadioOptions(denied); + expect(rescheduleBtn()).not.toBeInTheDocument(); + expect(scheduleLaterBtn()).not.toBeInTheDocument(); + }); + }); + }); + + describe('on entering a decision date into date selector', () => { + describe('date is in the future', () => { + const dateErrorMessage = 'Dates cannot be in the future'; + const tomorrow = add(new Date(), { days: 1 }); + + test('date error message appears', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + enterInputValue(datePrompt, tomorrow.toString()); + expect(screen.getByText(dateErrorMessage)).toBeInTheDocument(); + }); + }); + }); +}); diff --git a/client/test/app/queue/components/modalUtils.js b/client/test/app/queue/components/modalUtils.js index 480c3309dbb..9e79fbd788b 100644 --- a/client/test/app/queue/components/modalUtils.js +++ b/client/test/app/queue/components/modalUtils.js @@ -1,5 +1,5 @@ import userEvent from '@testing-library/user-event'; -import { screen } from '@testing-library/react'; +import { screen, fireEvent } from '@testing-library/react'; import * as uiActions from 'app/queue/uiReducer/uiActions'; /** @@ -47,6 +47,17 @@ export const enterTextFieldOptions = (instructionsFieldName, instructions) => { userEvent.type(instructionsField, instructions); }; +/** + * Finds an input in the component and enters the specified text + * @param {string} inputLabelName -- Label name of the input field to be populated + * @param {string} textValue -- The string to enter into the input field + */ +export const enterInputValue = (inputLabelName, textValue) => { + const inputField = screen.getByLabelText(inputLabelName); + + fireEvent.change(inputField, { target: { value: textValue }}); +}; + /** * Enters the specified number of days into a number field * @param {string} customFieldName -- Role name of the field to be populated diff --git a/client/test/data/queue/taskActionModals/taskActionModalData.js b/client/test/data/queue/taskActionModals/taskActionModalData.js index 56329e28ee5..ee6de1a4ced 100644 --- a/client/test/data/queue/taskActionModals/taskActionModalData.js +++ b/client/test/data/queue/taskActionModals/taskActionModalData.js @@ -1787,4 +1787,543 @@ export const camoToProgramOfficeToCamoData = { }, ...uiData, }; + +const hearingPostponementRequestMailTaskData = { + 12570: { + uniqueId: '12570', + isLegacy: false, + type: 'HearingPostponementRequestMailTask', + appealType: 'Appeal', + addedByCssId: null, + appealId: 1161, + externalAppealId: '2f316d14-7ae6-4255-8f83-e0489ad5005d', + assignedOn: '2023-07-28T14:20:26.457-04:00', + closestRegionalOffice: null, + createdAt: '2023-07-28T14:20:26.457-04:00', + closedAt: null, + startedAt: null, + assigneeName: 'Hearing Admin', + assignedTo: { + cssId: null, + name: 'Hearing Admin', + id: 37, + isOrganization: true, + type: 'HearingAdmin' + }, + assignedBy: { + firstName: 'Huan', + lastName: 'Tiryaki', + cssId: 'JOLLY_POSTMAN', + pgId: 81 + }, + completedBy: { + cssId: null + }, + cancelledBy: { + cssId: null + }, + cancelReason: null, + convertedBy: { + cssId: null + }, + convertedOn: null, + taskId: '12570', + parentId: 12569, + label: 'Hearing postponement request', + documentId: null, + externalHearingId: null, + workProduct: null, + caseType: 'Original', + aod: false, + previousTaskAssignedOn: null, + placedOnHoldAt: null, + status: 'assigned', + onHoldDuration: null, + instructions: [ + 'test' + ], + decisionPreparedBy: null, + availableActions: [ + { + label: 'Change task type', + func: 'change_task_type_data', + value: 'modal/change_task_type', + data: { + options: [ + { + value: 'CavcCorrespondenceMailTask', + label: 'CAVC Correspondence' + }, + { + value: 'ClearAndUnmistakeableErrorMailTask', + label: 'CUE-related' + }, + { + value: 'AddressChangeMailTask', + label: 'Change of address' + }, + { + value: 'CongressionalInterestMailTask', + label: 'Congressional interest' + }, + { + value: 'ControlledCorrespondenceMailTask', + label: 'Controlled correspondence' + }, + { + value: 'DeathCertificateMailTask', + label: 'Death certificate' + }, + { + value: 'EvidenceOrArgumentMailTask', + label: 'Evidence or argument' + }, + { + value: 'ExtensionRequestMailTask', + label: 'Extension request' + }, + { + value: 'FoiaRequestMailTask', + label: 'FOIA request' + }, + { + value: 'HearingPostponementRequestMailTask', + label: 'Hearing postponement request' + }, + { + value: 'HearingRelatedMailTask', + label: 'Hearing-related' + }, + { + value: 'ReconsiderationMotionMailTask', + label: 'Motion for reconsideration' + }, + { + value: 'AodMotionMailTask', + label: 'Motion to Advance on Docket' + }, + { + value: 'OtherMotionMailTask', + label: 'Other motion' + }, + { + value: 'PowerOfAttorneyRelatedMailTask', + label: 'Power of attorney-related' + }, + { + value: 'PrivacyActRequestMailTask', + label: 'Privacy act request' + }, + { + value: 'PrivacyComplaintMailTask', + label: 'Privacy complaint' + }, + { + value: 'ReturnedUndeliverableCorrespondenceMailTask', + label: 'Returned or undeliverable mail' + }, + { + value: 'StatusInquiryMailTask', + label: 'Status inquiry' + }, + { + value: 'AppealWithdrawalMailTask', + label: 'Withdrawal of appeal' + } + ] + } + }, + { + label: 'Mark as complete', + value: 'modal/complete_and_postpone' + }, + { + label: 'Assign to team', + func: 'assign_to_organization_data', + value: 'modal/assign_to_team', + data: { + selected: null, + options: [ + { + label: 'Board Dispatch', + value: 1 + }, + { + label: 'Case Review', + value: 2 + }, + { + label: 'Case Movement Team', + value: 3 + }, + { + label: 'BVA Intake', + value: 4 + }, + { + label: 'VLJ Support Staff', + value: 6 + }, + { + label: 'Transcription', + value: 7 + }, + { + label: 'National Cemetery Administration', + value: 11 + }, + { + label: 'Translation', + value: 12 + }, + { + label: 'Quality Review', + value: 13 + }, + { + label: 'AOD', + value: 14 + }, + { + label: 'Mail', + value: 15 + }, + { + label: 'Privacy Team', + value: 16 + }, + { + label: 'Litigation Support', + value: 17 + }, + { + label: 'Office of Assessment and Improvement', + value: 18 + }, + { + label: 'Office of Chief Counsel', + value: 19 + }, + { + label: 'CAVC Litigation Support', + value: 20 + }, + { + label: 'Pulac-Cerullo', + value: 21 + }, + { + label: 'Hearings Management', + value: 36 + }, + { + label: 'VLJ Support Staff', + value: 2000000023 + }, + { + label: 'Education', + value: 2000000219 + }, + { + label: 'Veterans Readiness and Employment', + value: 2000000220 + }, + { + label: 'Loan Guaranty', + value: 2000000221 + }, + { + label: 'Veterans Health Administration', + value: 2000000222 + }, + { + label: 'Pension & Survivor\'s Benefits', + value: 2000000590 + }, + { + label: 'Fiduciary', + value: 2000000591 + }, + { + label: 'Compensation', + value: 2000000592 + }, + { + label: 'Insurance', + value: 2000000593 + }, + { + label: 'Executive Management Office', + value: 64 + } + ], + type: 'HearingPostponementRequestMailTask' + } + }, + { + label: 'Assign to person', + func: 'assign_to_user_data', + value: 'modal/assign_to_person', + data: { + selected: { + id: 125, + last_login_at: '2023-07-31T15:10:08.273-04:00', + station_id: '101', + full_name: 'Stacy BuildAndEditHearingSchedule Yellow', + email: null, + roles: [ + 'Edit HearSched', + 'Build HearSched' + ], + created_at: '2023-07-26T08:53:05.164-04:00', + css_id: 'BVASYELLOW', + efolder_documents_fetched_at: null, + selected_regional_office: null, + status: 'active', + status_updated_at: null, + updated_at: '2023-07-31T15:10:08.277-04:00', + display_name: 'BVASYELLOW (VACO)' + }, + options: [ + { + label: 'Theresa BuildHearingSchedule Warner', + value: 10 + }, + { + label: 'Felicia BuildAndEditHearingSchedule Orange', + value: 126 + }, + { + label: 'Gail Maggio V', + value: 2000001601 + }, + { + label: 'Amb. Cherelle Crist', + value: 2000001881 + }, + { + label: 'LETITIA SCHUSTER', + value: 2000014300 + }, + { + label: 'Manie Bahringer', + value: 2000000784 + }, + { + label: 'Young Metz', + value: 2000001481 + }, + { + label: 'Tena Green DDS', + value: 2000001607 + }, + { + label: 'Horace Paucek', + value: 2000001608 + }, + { + label: 'Angelo Harvey', + value: 2000001752 + }, + { + label: 'Shu Wilkinson II', + value: 2000001822 + }, + { + label: 'Eugene Waelchi JD', + value: 2000001944 + }, + { + label: 'Bernadine Lindgren', + value: 2000002011 + }, + { + label: 'Lenna Roberts', + value: 2000002061 + }, + { + label: 'Dedra Kassulke', + value: 2000002114 + }, + { + label: 'Judy Douglas', + value: 2000002117 + }, + { + label: 'Yuki Green', + value: 2000002170 + }, + { + label: 'Hassan Considine', + value: 2000002309 + }, + { + label: 'Cecilia Feeney', + value: 2000002311 + }, + { + label: 'Shizue Orn', + value: 2000002324 + }, + { + label: 'Marcia Turcotte DDS', + value: 2000003937 + }, + { + label: 'Mrs. Roderick Boyle', + value: 2000008710 + }, + { + label: 'Rep. Trey Leuschke', + value: 2000009340 + }, + { + label: 'Malka Lind MD', + value: 2000010066 + }, + { + label: 'Derrick Abernathy', + value: 2000011140 + }, + { + label: 'Ramon Bode', + value: 2000011189 + }, + { + label: 'Consuelo Rice VM', + value: 2000011783 + }, + { + label: 'Robt Reinger', + value: 2000013679 + }, + { + label: 'Cruz Kulas', + value: 2000014113 + }, + { + label: 'Jeremy Abbott', + value: 2000014115 + }, + { + label: 'Lexie Kunze', + value: 2000014117 + }, + { + label: 'Jenny Kiehn', + value: 2000014742 + }, + { + label: 'Justin Greenholt', + value: 2000016249 + }, + { + label: 'Tiffani Heller', + value: 2000016344 + }, + { + label: 'Cris Kris', + value: 2000016552 + }, + { + label: 'The Hon. Collin Johnston', + value: 2000016711 + }, + { + label: 'Susanna Bahringer DDS', + value: 2000020664 + }, + { + label: 'Rev. Eric Howell', + value: 2000021430 + }, + { + label: 'Anthony Greenfelder', + value: 2000021431 + }, + { + label: 'Sen. Bradley Lehner', + value: 2000021462 + }, + { + label: 'Arden Boyle', + value: 2000021472 + }, + { + label: 'Millard Dach CPA', + value: 2000021486 + }, + { + label: 'Phung Reichert DC', + value: 2000021537 + }, + { + label: 'Harvey Jenkins', + value: 2000021577 + }, + { + label: 'DINO VONRUEDEN', + value: 2000003482 + }, + { + label: 'ISREAL D\'AMORE', + value: 2000003782 + }, + { + label: 'MAMMIE TREUTEL', + value: 2000014114 + }, + { + label: 'Stacy BuildAndEditHearingSchedule Yellow', + value: 125 + } + ], + type: 'HearingPostponementRequestMailTask' + } + }, + { + label: 'Cancel task', + func: 'cancel_task_data', + value: 'modal/cancel_task', + data: { + modal_title: 'Cancel task', + modal_body: 'Cancelling this task will return it to Huan MailUser Tiryaki', + message_title: 'Task for Isaiah Davis\'s case has been cancelled', + message_detail: 'If you have made a mistake, please email Huan MailUser Tiryaki to manage any changes.' + } + } + ], + timelineTitle: 'HearingPostponementRequestMailTask completed', + hideFromQueueTableView: false, + hideFromTaskSnapshot: false, + hideFromCaseTimeline: false, + availableHearingLocations: [], + latestInformalHearingPresentationTask: {}, + canMoveOnDocketSwitch: true, + timerEndsAt: null, + unscheduledHearingNotes: {}, + ownedBy: 'Hearing Admin', + daysSinceLastStatusChange: 3, + daysSinceBoardIntake: 3, + id: '12570', + claimant: {}, + appeal_receipt_date: '2023-07-02' + } +}; + +export const completeHearingPostponementRequestData = { + queue: { + amaTasks: { + ...hearingPostponementRequestMailTaskData, + }, + appeals: { + '2f316d14-7ae6-4255-8f83-e0489ad5005d': { + id: '1161', + externalId: '2f316d14-7ae6-4255-8f83-e0489ad5005d', + }, + }, + }, + ...uiData +}; + /* eslint-enable max-lines */ From fff5e0c5bc003b1f1655a20fff60f841d4268abd Mon Sep 17 00:00:00 2001 From: Minhazur Rahaman Date: Tue, 1 Aug 2023 17:12:55 -0400 Subject: [PATCH 31/87] APPEALS-25000 added feature test for assigning to team --- spec/feature/queue/mail_task_spec.rb | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/spec/feature/queue/mail_task_spec.rb b/spec/feature/queue/mail_task_spec.rb index 0b2b1ed41e9..2aa8f88486b 100644 --- a/spec/feature/queue/mail_task_spec.rb +++ b/spec/feature/queue/mail_task_spec.rb @@ -146,24 +146,35 @@ end describe "Hearing Postponement Request Mail Task" do - let(:distribution_task) { create(:distribution_task) } - let!(:schedule_hearing_task) do - ScheduleHearingTask.create( - appeal: distribution_task.appeal, - parent_id: distribution_task.id, - assigned_to: Bva.singleton - ) + before do + HearingAdmin.singleton.add_user(User.current_user) end let(:hpr_task) { create(:hearing_postponement_request_mail_task, :with_unscheduled_hearing) } it "change task type" do - HearingAdmin.singleton.add_user(User.current_user) visit("queue/appeals/#{hpr_task.appeal.uuid}") click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: COPY::CHANGE_TASK_TYPE_SUBHEAD) find(".cf-select__control", text: "Select an action type").click find(".cf-select__option", text: "Change of address").click fill_in(name: "Provide instructions and context for this change:", with: "instructions") click_button("Change task type") + most_recent_task = find("tr", text: "TASK", match: :first) + expect(most_recent_task).to have_content("TASK\nChange of address") + expect(most_recent_task).to have_content("ASSIGNED ON\n" + Time.zone.today.strftime("%m/%d/%Y").to_s) + end + + it "assign to team" do + page = "queue/appeals/#{hpr_task.appeal.uuid}" + visit(page) + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.ASSIGN_TO_TEAM.label) + find(".cf-select__control", text: "Select a team").click + find(".cf-select__option", text: "Case Review").click + fill_in(name: "Provide instructions and context for this action:", with: "instructions") + click_button("Submit") + visit(page) + most_recent_task = find("tr", text: "TASK", match: :first) + expect(most_recent_task).to have_content("ASSIGNED TO\nCase Review") + expect(most_recent_task).to have_content(Time.zone.today.strftime("%m/%d/%Y").to_s) end end end From adec79229f7c59cd6db6a5044ffc019e40b20f82 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Wed, 2 Aug 2023 11:04:45 -0400 Subject: [PATCH 32/87] Created test for date selector --- ...eteHearingPostponementRequestModal.test.js | 25 ++++++++++++++++--- .../test/app/queue/components/modalUtils.js | 8 ++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js index afdb7286fb6..7e5c48b72f0 100644 --- a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js +++ b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js @@ -16,7 +16,7 @@ import { enterInputValue } from '../modalUtils'; import COPY from '../../../../../COPY'; -import { add } from 'date-fns'; +import { add, format } from 'date-fns'; const renderCompleteHprModal = (storeValues) => { const appealId = getAppealId(storeValues); @@ -134,15 +134,32 @@ describe('CompleteHearingPostponementRequestModal', () => { }); describe('on entering a decision date into date selector', () => { + const dateErrorMessage = 'Dates cannot be in the future'; + const formatDate = (date) => format(date, 'yyyy-MM-dd').toString(); + describe('date is in the future', () => { - const dateErrorMessage = 'Dates cannot be in the future'; - const tomorrow = add(new Date(), { days: 1 }); + const tomorrow = formatDate(add(new Date(), { days: 1 })); test('date error message appears', () => { renderCompleteHprModal(completeHearingPostponementRequestData); - enterInputValue(datePrompt, tomorrow.toString()); + enterInputValue(datePrompt, tomorrow); expect(screen.getByText(dateErrorMessage)).toBeInTheDocument(); + + // TEST THAT BUTTON IS DISABLED IF ALL OTHER FIELDS VALID + }); + }); + + describe('date is not in the future', () => { + const today = formatDate(new Date()); + + test('date error message is not present', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + enterInputValue(datePrompt, today); + expect(screen.queryByText(dateErrorMessage)).not.toBeInTheDocument(); + + // TEST THAT BUTTON IS ENABLED IF ALL OTHER FIELDS VALID }); }); }); diff --git a/client/test/app/queue/components/modalUtils.js b/client/test/app/queue/components/modalUtils.js index 9e79fbd788b..0a92050c85b 100644 --- a/client/test/app/queue/components/modalUtils.js +++ b/client/test/app/queue/components/modalUtils.js @@ -51,11 +51,15 @@ export const enterTextFieldOptions = (instructionsFieldName, instructions) => { * Finds an input in the component and enters the specified text * @param {string} inputLabelName -- Label name of the input field to be populated * @param {string} textValue -- The string to enter into the input field + * Note: The 'inputValue' must use ISO 8601 format when firing a + * change event on an input of type "date." + * - valid date inputValue: '2020-05-24' + * - invalid date inputValue: '24/05/2020' */ -export const enterInputValue = (inputLabelName, textValue) => { +export const enterInputValue = (inputLabelName, inputValue) => { const inputField = screen.getByLabelText(inputLabelName); - fireEvent.change(inputField, { target: { value: textValue }}); + fireEvent.change(inputField, { target: { value: inputValue } }); }; /** From 95b05017a23f0c4499dd80e14ac5e7895680db5a Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Wed, 2 Aug 2023 11:23:04 -0400 Subject: [PATCH 33/87] APPEALS-25001 Added comment to legacy mail tasks constant --- app/models/tasks/mail_task.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/tasks/mail_task.rb b/app/models/tasks/mail_task.rb index 4b2478f4340..c3709f2bda4 100644 --- a/app/models/tasks/mail_task.rb +++ b/app/models/tasks/mail_task.rb @@ -20,6 +20,8 @@ class MailTask < Task def verify_org_task_unique; end prepend PrivacyActPending + # This constant is more efficient than iterating through all mail tasks + # and filtering out almost all of them since only HPR and HWR are approved for now LEGACY_MAIL_TASKS = [ { label: "Hearing postponement request", value: "HearingPostponementRequestMailTask" } ].freeze From c2bb3c67bb71267471ecf3bdc3f513f4784c18cb Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Wed, 2 Aug 2023 12:51:12 -0400 Subject: [PATCH 34/87] APPEALS-25001 Uncomment line in tasks_for_appeal --- app/workflows/tasks_for_appeal.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/workflows/tasks_for_appeal.rb b/app/workflows/tasks_for_appeal.rb index 13ff885dbfa..dcd8719f592 100644 --- a/app/workflows/tasks_for_appeal.rb +++ b/app/workflows/tasks_for_appeal.rb @@ -79,7 +79,7 @@ def initialize_hearing_tasks_for_travel_board? end def legacy_appeal_tasks - # return [] unless user_is_judge_or_attorney? || user.can_act_on_behalf_of_judges? + return [] unless user_is_judge_or_attorney? || user.can_act_on_behalf_of_judges? LegacyWorkQueue.tasks_by_appeal_id(appeal.vacols_id) end From 265b5aaec28313fe054fb374ac39ad3b935f89f6 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Wed, 2 Aug 2023 12:51:53 -0400 Subject: [PATCH 35/87] APPEALS-24997 Updated modal utils and completed jest tests --- ...eteHearingPostponementRequestModal.test.js | 104 +++++++++++++++--- .../test/app/queue/components/modalUtils.js | 5 +- 2 files changed, 91 insertions(+), 18 deletions(-) diff --git a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js index 7e5c48b72f0..f4a555146b8 100644 --- a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js +++ b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js @@ -13,7 +13,8 @@ import { getAppealId, getTaskId, enterModalRadioOptions, - enterInputValue + enterInputValue, + enterTextFieldOptions } from '../modalUtils'; import COPY from '../../../../../COPY'; import { add, format } from 'date-fns'; @@ -41,16 +42,22 @@ const renderCompleteHprModal = (storeValues) => { }; describe('CompleteHearingPostponementRequestModal', () => { + const modalAction = 'Mark as complete'; const [granted, denied] = ['Granted', 'Denied']; const datePrompt = 'Date of ruling:'; const [reschedule, scheduleLater] = ['Reschedule immediately', 'Send to Schedule Veteran list']; + const instructions = `${COPY.PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL}:`; const rescheduleBtn = () => screen.queryByRole('radio', { name: reschedule }); const scheduleLaterBtn = () => screen.queryByRole('radio', { name: scheduleLater }); + const instructionsTextArea = () => screen.getByRole('textbox', { name: instructions }); + const submitButton = () => screen.getByRole('button', { name: modalAction }); - describe('on modal open', () => { - const modalAction = 'Mark as complete'; + const formatDate = (date) => format(date, 'yyyy-MM-dd').toString(); + const today = formatDate(new Date()); + const tomorrow = formatDate(add(new Date(), { days: 1 })); + describe('on modal open', () => { test('modal title: "Mark as complete"', () => { renderCompleteHprModal(completeHearingPostponementRequestData); @@ -84,12 +91,10 @@ describe('CompleteHearingPostponementRequestModal', () => { }); describe('text area field', () => { - const instructions = `${COPY.PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL}:`; - test('has text prompt "Provide instructions and context for this action:"', () => { renderCompleteHprModal(completeHearingPostponementRequestData); - expect(screen.getByRole('textbox', { name: instructions })).toBeInTheDocument(); + expect(instructionsTextArea()).toBeInTheDocument(); }); }); @@ -106,7 +111,7 @@ describe('CompleteHearingPostponementRequestModal', () => { test('submit button is initially disabled', () => { renderCompleteHprModal(completeHearingPostponementRequestData); - expect(screen.getByRole('button', { name: modalAction })).toBeDisabled(); + expect(submitButton()).toBeDisabled(); }); }); }); @@ -135,31 +140,100 @@ describe('CompleteHearingPostponementRequestModal', () => { describe('on entering a decision date into date selector', () => { const dateErrorMessage = 'Dates cannot be in the future'; - const formatDate = (date) => format(date, 'yyyy-MM-dd').toString(); describe('date is in the future', () => { - const tomorrow = formatDate(add(new Date(), { days: 1 })); - test('date error message appears', () => { renderCompleteHprModal(completeHearingPostponementRequestData); enterInputValue(datePrompt, tomorrow); expect(screen.getByText(dateErrorMessage)).toBeInTheDocument(); - - // TEST THAT BUTTON IS DISABLED IF ALL OTHER FIELDS VALID }); }); describe('date is not in the future', () => { - const today = formatDate(new Date()); - test('date error message is not present', () => { renderCompleteHprModal(completeHearingPostponementRequestData); enterInputValue(datePrompt, today); expect(screen.queryByText(dateErrorMessage)).not.toBeInTheDocument(); + }); + }); + }); + + describe('on validate form', () => { + const completeValidForm = (eventSequence) => { + for (const event in eventSequence) { + if (eventSequence[event]) { + eventSequence[event].call(); + } + } + }; + + const completeInvalidForm = (eventSequence, invalidEvent) => { + for (const event in eventSequence) { + if ( + eventSequence[event] && + event !== invalidEvent && + (invalidEvent === 'granted' && event !== 'reschedule') + ) { + eventSequence[event].call(); + } + } + }; + + const runInvalidationTestOnEachField = (eventSequence) => { + Object.keys(eventSequence).forEach((key) => { + describe(`${key} field is invalid`, () => { + test('submit button is disabled', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + completeInvalidForm(eventSequence, key); + expect(submitButton()).toBeDisabled(); + }); + }); + }); + }; + + describe('judge ruling is "Granted"', () => { + const validModalEvents = { + granted: () => enterModalRadioOptions(granted), + date: () => enterInputValue(datePrompt, today), + reschedule: () => enterModalRadioOptions(reschedule), + instructions: () => enterTextFieldOptions(instructions, 'test') + }; + + describe('all requried fields are valid', () => { + test('submit button is enabled', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + completeValidForm(validModalEvents); + expect(submitButton()).not.toBeDisabled(); + }); + }); + + describe('any field is invalid', () => { + runInvalidationTestOnEachField(validModalEvents); + }); + }); + + describe('judge ruling is "Denied"', () => { + const validModalEvents = { + denied: () => enterModalRadioOptions(denied), + date: () => enterInputValue(datePrompt, today), + instructions: () => enterTextFieldOptions(instructions, 'test') + }; + + describe('all requried fields are valid', () => { + test('submit button is enabled', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + completeValidForm(validModalEvents); + expect(submitButton()).not.toBeDisabled(); + }); + }); - // TEST THAT BUTTON IS ENABLED IF ALL OTHER FIELDS VALID + describe('any field is invalid', () => { + runInvalidationTestOnEachField(validModalEvents); }); }); }); diff --git a/client/test/app/queue/components/modalUtils.js b/client/test/app/queue/components/modalUtils.js index 0a92050c85b..739b75281ed 100644 --- a/client/test/app/queue/components/modalUtils.js +++ b/client/test/app/queue/components/modalUtils.js @@ -1,5 +1,5 @@ import userEvent from '@testing-library/user-event'; -import { screen, fireEvent } from '@testing-library/react'; +import { screen } from '@testing-library/react'; import * as uiActions from 'app/queue/uiReducer/uiActions'; /** @@ -59,7 +59,7 @@ export const enterTextFieldOptions = (instructionsFieldName, instructions) => { export const enterInputValue = (inputLabelName, inputValue) => { const inputField = screen.getByLabelText(inputLabelName); - fireEvent.change(inputField, { target: { value: inputValue } }); + userEvent.type(inputField, inputValue); }; /** @@ -104,7 +104,6 @@ export const clickSubmissionButton = (buttonText) => { userEvent.click(screen.getByRole('button', { name: buttonText })); }; - /** * Extracts the modal type from a TASK_ACTIONS.json entry * @param {string} taskActionValue -- Corresponds to TASK_ACTION..value - Typically "modal/" From 26ebcf28217ef6af4f805d9d850a3b2155a39e6c Mon Sep 17 00:00:00 2001 From: Minhazur Rahaman Date: Wed, 2 Aug 2023 12:54:28 -0400 Subject: [PATCH 36/87] APPEALS-25000 added in more feature tests --- spec/feature/queue/mail_task_spec.rb | 85 +++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 14 deletions(-) diff --git a/spec/feature/queue/mail_task_spec.rb b/spec/feature/queue/mail_task_spec.rb index 2aa8f88486b..bec03a4be7d 100644 --- a/spec/feature/queue/mail_task_spec.rb +++ b/spec/feature/queue/mail_task_spec.rb @@ -151,30 +151,87 @@ end let(:hpr_task) { create(:hearing_postponement_request_mail_task, :with_unscheduled_hearing) } - it "change task type" do - visit("queue/appeals/#{hpr_task.appeal.uuid}") - click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: COPY::CHANGE_TASK_TYPE_SUBHEAD) - find(".cf-select__control", text: "Select an action type").click - find(".cf-select__option", text: "Change of address").click - fill_in(name: "Provide instructions and context for this change:", with: "instructions") - click_button("Change task type") - most_recent_task = find("tr", text: "TASK", match: :first) - expect(most_recent_task).to have_content("TASK\nChange of address") - expect(most_recent_task).to have_content("ASSIGNED ON\n" + Time.zone.today.strftime("%m/%d/%Y").to_s) + context "changing task type" do + it "current tasks should have new task" do + visit("queue/appeals/#{hpr_task.appeal.uuid}") + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: COPY::CHANGE_TASK_TYPE_SUBHEAD) + find(".cf-select__control", text: "Select an action type").click + find(".cf-select__option", text: "Change of address").click + fill_in(name: "Provide instructions and context for this change:", with: "instructions") + click_button("Change task type") + most_recent_task = find("tr", text: "TASK", match: :first) + expect(most_recent_task).to have_content("ASSIGNED ON\n#{Time.zone.today.strftime('%m/%d/%Y')}") + expect(most_recent_task).to have_content("TASK\nChange of address") + end + + it "case timeline should cancel old task" do + visit("queue/appeals/#{hpr_task.appeal.uuid}") + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: COPY::CHANGE_TASK_TYPE_SUBHEAD) + find(".cf-select__control", text: "Select an action type").click + find(".cf-select__option", text: "Change of address").click + fill_in(name: "Provide instructions and context for this change:", with: "instructions") + click_button("Change task type") + first_task_item = find("#case-timeline-table tr:nth-child(2)") + expect(first_task_item).to have_content("CANCELLED ON\n#{Time.zone.today.strftime('%m/%d/%Y')}") + expect(first_task_item).to have_content("HearingPostponementRequestMailTask cancelled") + expect(first_task_item).to have_content("CANCELLED BY\n#{User.current_user.css_id}") + end end - it "assign to team" do + it "assigning to new team" do page = "queue/appeals/#{hpr_task.appeal.uuid}" visit(page) click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.ASSIGN_TO_TEAM.label) find(".cf-select__control", text: "Select a team").click - find(".cf-select__option", text: "Case Review").click + find(".cf-select__option", text: "BVA Intake").click fill_in(name: "Provide instructions and context for this action:", with: "instructions") click_button("Submit") visit(page) most_recent_task = find("tr", text: "TASK", match: :first) - expect(most_recent_task).to have_content("ASSIGNED TO\nCase Review") - expect(most_recent_task).to have_content(Time.zone.today.strftime("%m/%d/%Y").to_s) + expect(most_recent_task).to have_content("ASSIGNED ON\n#{Time.zone.today.strftime('%m/%d/%Y')}") + expect(most_recent_task).to have_content("ASSIGNED TO\nBVA Intake") + end + + it "assign to person" do + new_user = User.create!(css_id: "NEW_USER", full_name: "John Smith", station_id: "101") + HearingAdmin.singleton.add_user(new_user) + page = "queue/appeals/#{hpr_task.appeal.uuid}" + visit(page) + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.ASSIGN_TO_PERSON.label) + find(".cf-select__control", text: User.current_user.full_name).click + find(".cf-select__option", text: new_user.full_name).click + fill_in(name: "Provide instructions and context for this action:", with: "instructions") + click_button("Submit") + visit(page) + most_recent_task = find("tr", text: "TASK", match: :first) + expect(most_recent_task).to have_content("ASSIGNED ON\n#{Time.zone.today.strftime('%m/%d/%Y')}") + expect(most_recent_task).to have_content("ASSIGNED TO\n#{new_user.css_id}") + end + + context "cancelling task" do + it "should remove HearingPostponementRequestTask from current tasks" do + page = "queue/appeals/#{hpr_task.appeal.uuid}" + visit(page) + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.CANCEL_TASK.label) + fill_in(name: "Provide instructions and context for this action:", with: "instructions") + click_button("Submit") + visit(page) + most_recent_task = find("tr", text: "TASK", match: :first) + expect(most_recent_task).to have_content("TASK\nAll hearing-related tasks") + end + + it "case timeline should cancel task" do + page = "queue/appeals/#{hpr_task.appeal.uuid}" + visit(page) + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.CANCEL_TASK.label) + fill_in(name: "Provide instructions and context for this action:", with: "instructions") + click_button("Submit") + visit(page) + first_task_item = find("#case-timeline-table tr:nth-child(2)") + expect(first_task_item).to have_content("CANCELLED ON\n#{Time.zone.today.strftime('%m/%d/%Y')}") + expect(first_task_item).to have_content("HearingPostponementRequestMailTask cancelled") + expect(first_task_item).to have_content("CANCELLED BY\n#{User.current_user.css_id}") + end end end end From 268135c445572f924fc0f62d0d9ffda15933442e Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Wed, 2 Aug 2023 14:57:14 -0400 Subject: [PATCH 37/87] APPEALS-24996 Updated color to use existing variable name --- client/app/styles/_commons.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/app/styles/_commons.scss b/client/app/styles/_commons.scss index da69380d004..295967b8a57 100644 --- a/client/app/styles/_commons.scss +++ b/client/app/styles/_commons.scss @@ -482,7 +482,7 @@ svg title { } .cf-form-textarea { - color: #323A45; + color: $color-gray-dark; textarea { max-height: 120px; From 699fd1456a372a555dfa6bc1a124cbad524ad31c Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Wed, 2 Aug 2023 15:08:31 -0400 Subject: [PATCH 38/87] APPEALS-24997 refactored tests to fix code climate duplicate code --- ...eteHearingPostponementRequestModal.test.js | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js index f4a555146b8..48cbed1d0f2 100644 --- a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js +++ b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js @@ -169,6 +169,17 @@ describe('CompleteHearingPostponementRequestModal', () => { } }; + const testValidForm = (eventSequence) => { + describe('all requried fields are valid', () => { + test('submit button is enabled', () => { + renderCompleteHprModal(completeHearingPostponementRequestData); + + completeValidForm(eventSequence); + expect(submitButton()).not.toBeDisabled(); + }); + }); + }; + const completeInvalidForm = (eventSequence, invalidEvent) => { for (const event in eventSequence) { if ( @@ -202,14 +213,7 @@ describe('CompleteHearingPostponementRequestModal', () => { instructions: () => enterTextFieldOptions(instructions, 'test') }; - describe('all requried fields are valid', () => { - test('submit button is enabled', () => { - renderCompleteHprModal(completeHearingPostponementRequestData); - - completeValidForm(validModalEvents); - expect(submitButton()).not.toBeDisabled(); - }); - }); + testValidForm(validModalEvents); describe('any field is invalid', () => { runInvalidationTestOnEachField(validModalEvents); @@ -223,14 +227,7 @@ describe('CompleteHearingPostponementRequestModal', () => { instructions: () => enterTextFieldOptions(instructions, 'test') }; - describe('all requried fields are valid', () => { - test('submit button is enabled', () => { - renderCompleteHprModal(completeHearingPostponementRequestData); - - completeValidForm(validModalEvents); - expect(submitButton()).not.toBeDisabled(); - }); - }); + testValidForm(validModalEvents); describe('any field is invalid', () => { runInvalidationTestOnEachField(validModalEvents); From ee758e3e0577308f40b6740e412f7b53cf252c74 Mon Sep 17 00:00:00 2001 From: Minhazur Rahaman Date: Wed, 2 Aug 2023 15:35:54 -0400 Subject: [PATCH 39/87] APPEALS-25000 adjusted time check in feature tests --- spec/feature/queue/mail_task_spec.rb | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/spec/feature/queue/mail_task_spec.rb b/spec/feature/queue/mail_task_spec.rb index bec03a4be7d..908e520ba48 100644 --- a/spec/feature/queue/mail_task_spec.rb +++ b/spec/feature/queue/mail_task_spec.rb @@ -153,14 +153,16 @@ context "changing task type" do it "current tasks should have new task" do - visit("queue/appeals/#{hpr_task.appeal.uuid}") + appeal = hpr_task.appeal + visit("queue/appeals/#{appeal.uuid}") click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: COPY::CHANGE_TASK_TYPE_SUBHEAD) find(".cf-select__control", text: "Select an action type").click find(".cf-select__option", text: "Change of address").click fill_in(name: "Provide instructions and context for this change:", with: "instructions") click_button("Change task type") + new_task = appeal.tasks.last most_recent_task = find("tr", text: "TASK", match: :first) - expect(most_recent_task).to have_content("ASSIGNED ON\n#{Time.zone.today.strftime('%m/%d/%Y')}") + expect(most_recent_task).to have_content("ASSIGNED ON\n#{new_task.assigned_at.strftime('%m/%d/%Y')}") expect(most_recent_task).to have_content("TASK\nChange of address") end @@ -172,39 +174,43 @@ fill_in(name: "Provide instructions and context for this change:", with: "instructions") click_button("Change task type") first_task_item = find("#case-timeline-table tr:nth-child(2)") - expect(first_task_item).to have_content("CANCELLED ON\n#{Time.zone.today.strftime('%m/%d/%Y')}") + expect(first_task_item).to have_content("CANCELLED ON\n#{hpr_task.updated_at.strftime('%m/%d/%Y')}") expect(first_task_item).to have_content("HearingPostponementRequestMailTask cancelled") expect(first_task_item).to have_content("CANCELLED BY\n#{User.current_user.css_id}") end end it "assigning to new team" do - page = "queue/appeals/#{hpr_task.appeal.uuid}" + appeal = hpr_task.appeal + page = "queue/appeals/#{appeal.uuid}" visit(page) click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.ASSIGN_TO_TEAM.label) find(".cf-select__control", text: "Select a team").click find(".cf-select__option", text: "BVA Intake").click fill_in(name: "Provide instructions and context for this action:", with: "instructions") click_button("Submit") + new_task = appeal.tasks.last visit(page) most_recent_task = find("tr", text: "TASK", match: :first) - expect(most_recent_task).to have_content("ASSIGNED ON\n#{Time.zone.today.strftime('%m/%d/%Y')}") + expect(most_recent_task).to have_content("ASSIGNED ON\n#{new_task.assigned_at.strftime('%m/%d/%Y')}") expect(most_recent_task).to have_content("ASSIGNED TO\nBVA Intake") end it "assign to person" do new_user = User.create!(css_id: "NEW_USER", full_name: "John Smith", station_id: "101") HearingAdmin.singleton.add_user(new_user) - page = "queue/appeals/#{hpr_task.appeal.uuid}" + appeal = hpr_task.appeal + page = "queue/appeals/#{appeal.uuid}" visit(page) click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.ASSIGN_TO_PERSON.label) find(".cf-select__control", text: User.current_user.full_name).click find(".cf-select__option", text: new_user.full_name).click fill_in(name: "Provide instructions and context for this action:", with: "instructions") click_button("Submit") + new_task = appeal.tasks.last visit(page) most_recent_task = find("tr", text: "TASK", match: :first) - expect(most_recent_task).to have_content("ASSIGNED ON\n#{Time.zone.today.strftime('%m/%d/%Y')}") + expect(most_recent_task).to have_content("ASSIGNED ON\n#{new_task.assigned_at.strftime('%m/%d/%Y')}") expect(most_recent_task).to have_content("ASSIGNED TO\n#{new_user.css_id}") end @@ -228,7 +234,7 @@ click_button("Submit") visit(page) first_task_item = find("#case-timeline-table tr:nth-child(2)") - expect(first_task_item).to have_content("CANCELLED ON\n#{Time.zone.today.strftime('%m/%d/%Y')}") + expect(first_task_item).to have_content("CANCELLED ON\n#{hpr_task.updated_at.strftime('%m/%d/%Y')}") expect(first_task_item).to have_content("HearingPostponementRequestMailTask cancelled") expect(first_task_item).to have_content("CANCELLED BY\n#{User.current_user.css_id}") end From b926d325e70ff8cfe7b54b4f82c6068c67ca15df Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Wed, 2 Aug 2023 17:04:40 -0400 Subject: [PATCH 40/87] APPEALS-24997 uncommented out jestSetup line --- client/test/app/jestSetup.js | 2 +- db/schema.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/client/test/app/jestSetup.js b/client/test/app/jestSetup.js index 3a3e60f15ca..e8fb9d3cc41 100644 --- a/client/test/app/jestSetup.js +++ b/client/test/app/jestSetup.js @@ -13,7 +13,7 @@ global.scrollTo = jest.fn(); // Spy to ignore console warnings jest.spyOn(console, 'warn').mockReturnValue(); -// jest.spyOn(console, 'log').mockReturnValue(); +jest.spyOn(console, 'log').mockReturnValue(); jest.spyOn(console, 'error').mockReturnValue(); // Mock the Date generated for all tests diff --git a/db/schema.rb b/db/schema.rb index 0fa2ef9ac77..5c15532cc78 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -597,6 +597,8 @@ t.string "diagnostic_code", comment: "If a decision resulted in a rating, this is the rating issue's diagnostic code." t.string "disposition", comment: "The disposition for a decision issue. Dispositions made in Caseflow and dispositions made in VBMS can have different values." t.date "end_product_last_action_date", comment: "After an end product gets synced with a status of CLR (cleared), the end product's last_action_date is saved on any decision issues that are created as a result. This is used as a proxy for decision date for non-rating issues that are processed in VBMS because they don't have a rating profile date, and the exact decision date is not available." + t.boolean "mst_status", default: false, comment: "Indicates if decision issue is related to Military Sexual Trauma (MST)" + t.boolean "pact_status", default: false, comment: "Indicates if decision issue is related to Promise to Address Comprehensive Toxics (PACT) Act" t.string "participant_id", null: false, comment: "The Veteran's participant id." t.string "percent_number", comment: "percent_number from RatingIssue (prcntNo from Rating Profile)" t.string "rating_issue_reference_id", comment: "Identifies the specific issue on the rating that resulted from the decision issue (a rating issue can be connected to multiple contentions)." @@ -1472,9 +1474,13 @@ t.string "ineligible_reason", comment: "The reason for a Request Issue being ineligible. If a Request Issue has an ineligible_reason, it is still captured, but it will not get a contention in VBMS or a decision." t.boolean "is_predocket_needed", comment: "Indicates whether or not an issue has been selected to go to the pre-docket queue opposed to normal docketing." t.boolean "is_unidentified", comment: "Indicates whether a Request Issue is unidentified, meaning it wasn't found in the list of contestable issues, and is not a new nonrating issue. Contentions for unidentified issues are created on a rating End Product if processed in VBMS but without the issue description, and someone is required to edit it in Caseflow before proceeding with the decision." + t.boolean "mst_status", default: false, comment: "Indicates if issue is related to Military Sexual Trauma (MST)" + t.text "mst_status_update_reason_notes", comment: "The reason for why Request Issue is Military Sexual Trauma (MST)" t.string "nonrating_issue_category", comment: "The category selected for nonrating request issues. These vary by business line." t.string "nonrating_issue_description", comment: "The user entered description if the issue is a nonrating issue" t.text "notes", comment: "Notes added by the Claims Assistant when adding request issues. This may be used to capture handwritten notes on the form, or other comments the CA wants to capture." + t.boolean "pact_status", default: false, comment: "Indicates if issue is related to Promise to Address Comprehensive Toxics (PACT) Act" + t.text "pact_status_update_reason_notes", comment: "The reason for why Request Issue is Promise to Address Comprehensive Toxics (PACT) Act" t.string "ramp_claim_id", comment: "If a rating issue was created as a result of an issue intaken for a RAMP Review, it will be connected to the former RAMP issue by its End Product's claim ID." t.datetime "rating_issue_associated_at", comment: "Timestamp when a contention and its contested rating issue are associated in VBMS." t.string "split_issue_status", comment: "If a request issue is part of a split, on_hold status applies to the original request issues while active are request issues on splitted appeals" @@ -1485,6 +1491,8 @@ t.datetime "updated_at", comment: "Automatic timestamp whenever the record changes." t.string "vacols_id", comment: "The vacols_id of the legacy appeal that had an issue found to match the request issue." t.integer "vacols_sequence_id", comment: "The vacols_sequence_id, for the specific issue on the legacy appeal which the Claims Assistant determined to match the request issue on the Decision Review. A combination of the vacols_id (for the legacy appeal), and vacols_sequence_id (for which issue on the legacy appeal), is required to identify the issue being opted-in." + t.boolean "vbms_mst_status", default: false, comment: "Indicates if issue is related to Military Sexual Trauma (MST) and was imported from VBMS" + t.boolean "vbms_pact_status", default: false, comment: "Indicates if issue is related to Promise to Address Comprehensive Toxics (PACT) Act and was imported from VBMS" t.boolean "verified_unidentified_issue", comment: "A verified unidentified issue allows an issue whose rating data is missing to be intaken as a regular rating issue. In order to be marked as verified, a VSR needs to confirm that they were able to find the record of the decision for the issue." t.string "veteran_participant_id", comment: "The veteran participant ID. This should be unique in upstream systems and used in the future to reconcile duplicates." t.index ["closed_at"], name: "index_request_issues_on_closed_at" @@ -1510,6 +1518,8 @@ t.integer "edited_request_issue_ids", comment: "An array of the request issue IDs that were edited during this request issues update", array: true t.string "error", comment: "The error message if the last attempt at processing the request issues update was not successful." t.datetime "last_submitted_at", comment: "Timestamp for when the processing for the request issues update was last submitted. Used to determine how long to continue retrying the processing job. Can be reset to allow for additional retries." + t.integer "mst_edited_request_issue_ids", comment: "An array of the request issue IDs that were updated to be associated with MST in request issues update", array: true + t.integer "pact_edited_request_issue_ids", comment: "An array of the request issue IDs that were updated to be associated with PACT in request issues update", array: true t.datetime "processed_at", comment: "Timestamp for when the request issue update successfully completed processing." t.bigint "review_id", null: false, comment: "The ID of the decision review edited." t.string "review_type", null: false, comment: "The type of the decision review edited." @@ -1558,6 +1568,26 @@ t.index ["sent_by_id"], name: "index_sent_hearing_email_events_on_sent_by_id" end + create_table "special_issue_changes", force: :cascade do |t| + t.bigint "appeal_id", null: false, comment: "AMA or Legacy Appeal ID that the issue is tied to" + t.string "appeal_type", null: false, comment: "Appeal Type (Appeal or LegacyAppeal)" + t.string "change_category", null: false, comment: "Type of change that occured to the issue (Established Issue, Added Issue, Edited Issue, Removed Issue)" + t.datetime "created_at", null: false, comment: "Date the special issue change was made" + t.string "created_by_css_id", null: false, comment: "CSS ID of the user that made the special issue change" + t.bigint "created_by_id", null: false, comment: "User ID of the user that made the special issue change" + t.bigint "decision_issue_id", comment: "ID of the decision issue that had a special issue change from its corresponding request issue" + t.bigint "issue_id", null: false, comment: "ID of the issue that was changed" + t.boolean "mst_from_vbms", comment: "Indication that the MST status originally came from VBMS on intake" + t.string "mst_reason_for_change", comment: "Reason for changing the MST status on an issue" + t.boolean "original_mst_status", null: false, comment: "Original MST special issue status of the issue" + t.boolean "original_pact_status", null: false, comment: "Original PACT special issue status of the issue" + t.boolean "pact_from_vbms" + t.string "pact_reason_for_change", comment: "Reason for changing the PACT status on an issue" + t.bigint "task_id", null: false, comment: "Task ID of the IssueUpdateTask or EstablishmentTask used to log this issue in the case timeline" + t.boolean "updated_mst_status", comment: "Updated MST special issue status of the issue" + t.boolean "updated_pact_status", comment: "Updated PACT special issue status of the issue" + end + create_table "special_issue_lists", comment: "Associates special issues to an AMA or legacy appeal for Caseflow Queue. Caseflow Dispatch uses special issues stored in legacy_appeals. They are intentionally disconnected.", force: :cascade do |t| t.bigint "appeal_id", comment: "The ID of the appeal associated with this record" t.string "appeal_type", comment: "The type of appeal associated with this record" From 8f2cacbb65225b7970aef1cf0a2eef16a2509ad2 Mon Sep 17 00:00:00 2001 From: Marc Steele Date: Thu, 3 Aug 2023 10:20:36 -0400 Subject: [PATCH 41/87] APPEALS-25001 Update all relevant rspec --- spec/models/tasks/root_task_spec.rb | 8 +++++ .../task_action_repository_spec.rb | 30 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/spec/models/tasks/root_task_spec.rb b/spec/models/tasks/root_task_spec.rb index 732a08f9405..10c98b498bd 100644 --- a/spec/models/tasks/root_task_spec.rb +++ b/spec/models/tasks/root_task_spec.rb @@ -28,6 +28,14 @@ expect(subject).to eq([]) end end + + context "when the appeal is a legacy appeal" do + it "mail team members still have the option to add mail tasks" do + allow(user).to receive(:organizations).and_return([MailTeam.singleton]) + + expect(subject).to eq([root_task.build_action_hash(Constants.TASK_ACTIONS.CREATE_MAIL_TASK.to_h, user)]) + end + end end describe ".update_children_status_after_closed" do diff --git a/spec/repositories/task_action_repository_spec.rb b/spec/repositories/task_action_repository_spec.rb index 05becafc709..459ce45fa9b 100644 --- a/spec/repositories/task_action_repository_spec.rb +++ b/spec/repositories/task_action_repository_spec.rb @@ -120,6 +120,36 @@ end end + describe "#mail_assign_to_organization_data" do + context "outcoded Appeal" do + let(:appeal) { create(:appeal, :outcoded) } + subject { TaskActionRepository.mail_assign_to_organization_data(appeal.root_task) } + + it "returns all of the options when outcoded" do + expect(subject[:options]).to eq(MailTask.descendant_routing_options) + end + end + + context "active Appeal" do + let(:appeal) { create(:appeal, :active) } + subject { TaskActionRepository.mail_assign_to_organization_data(appeal.root_task) } + + it "returns all of the options except VacateMotionMailTask when not outcoded" do + expect(subject[:options]).to eq(MailTask.descendant_routing_options.reject do |opt| + opt[:value] == "VacateMotionMailTask" + end) + end + end + + context "LegacyAppeal" do + let(:appeal) { create(:legacy_appeal, :with_root_task) } + subject { TaskActionRepository.mail_assign_to_organization_data(appeal.root_task) } + it "returns only the HPR and HWR options" do + expect(subject[:options]).to eq(MailTask::LEGACY_MAIL_TASKS) + end + end + end + describe "#vha caregiver support task actions" do describe "#vha_caregiver_support_return_to_board_intake" do let(:user) { create(:user) } From 3eaac1932781a1704bf7c601df119ef226cfef31 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Thu, 3 Aug 2023 11:27:38 -0400 Subject: [PATCH 42/87] APPEALS-24997 refactored all 'Provide instructions and context for this action' copy under same variable name across caseflow --- app/repositories/task_action_repository.rb | 16 ++++++++-------- client/COPY.json | 3 --- client/app/queue/AssignToView.jsx | 2 +- client/app/queue/CreateMailTaskDialog.jsx | 2 +- .../AddAdminTaskForm/AddAdminTaskForm.jsx | 4 ++-- .../colocatedTasks/AddColocatedTaskForm.jsx | 2 +- .../queue/components/AssignToAttorneyWidget.jsx | 2 +- client/app/queue/components/CancelTaskModal.jsx | 4 ++-- .../returnToJudge/ReturnToJudgeModal.jsx | 4 ++-- .../app/queue/components/CancelTaskModal.test.js | 4 ++-- .../queue/components/CompleteTaskModal.test.js | 2 +- .../hearings/change_hearing_disposition_spec.rb | 4 ++-- .../schedule_veteran/build_hearsched_spec.rb | 8 ++++---- spec/feature/queue/ama_queue_spec.rb | 4 ++-- spec/feature/queue/case_assignment_spec.rb | 10 +++++----- spec/feature/queue/colocated_task_queue_spec.rb | 2 +- spec/feature/queue/docket_switch_spec.rb | 2 +- spec/feature/queue/judge_assignment_spec.rb | 6 +++--- spec/feature/queue/motion_to_vacate_spec.rb | 4 ++-- spec/feature/queue/pre_docket_spec.rb | 10 +++++----- spec/feature/queue/scm_judge_assignment_spec.rb | 4 ++-- spec/feature/queue/task_queue_spec.rb | 4 ++-- spec/fixes/investigate_scm_cant_reassign_spec.rb | 2 +- 23 files changed, 51 insertions(+), 54 deletions(-) diff --git a/app/repositories/task_action_repository.rb b/app/repositories/task_action_repository.rb index 23c321fdb59..69a4c812353 100644 --- a/app/repositories/task_action_repository.rb +++ b/app/repositories/task_action_repository.rb @@ -586,7 +586,7 @@ def docket_appeal_data(task, _user) modal_body: format(COPY::DOCKET_APPEAL_MODAL_BODY, pre_docket_org), modal_button_text: COPY::MODAL_CONFIRM_BUTTON, modal_alert: COPY::DOCKET_APPEAL_MODAL_NOTICE, - instructions_label: COPY::PRE_DOCKET_MODAL_BODY, + instructions_label: COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, redirect_after: "/organizations/#{BvaIntake.singleton.url}" } end @@ -640,7 +640,7 @@ def vha_assign_to_program_office_data(*) modal_title: COPY::VHA_ASSIGN_TO_PROGRAM_OFFICE_MODAL_TITLE, modal_button_text: COPY::MODAL_ASSIGN_BUTTON, modal_selector_placeholder: COPY::VHA_PROGRAM_OFFICE_SELECTOR_PLACEHOLDER, - instructions_label: COPY::PRE_DOCKET_MODAL_BODY, + instructions_label: COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, drop_down_label: COPY::VHA_CAMO_ASSIGN_TO_PROGRAM_OFFICE_DROPDOWN_LABEL, type: AssessDocumentationTask.name, redirect_after: "/organizations/#{VhaCamo.singleton.url}" @@ -708,7 +708,7 @@ def bva_intake_return_to_camo(task, _user) modal_title: COPY::BVA_INTAKE_RETURN_TO_CAMO_MODAL_TITLE, modal_body: COPY::BVA_INTAKE_RETURN_TO_CAMO_MODAL_BODY, modal_button_text: COPY::MODAL_RETURN_BUTTON, - instructions_label: COPY::PRE_DOCKET_MODAL_BODY, + instructions_label: COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, message_title: format(COPY::BVA_INTAKE_RETURN_TO_CAMO_CONFIRMATION_TITLE, task.appeal.veteran_full_name), type: VhaDocumentSearchTask.name, redirect_after: "/organizations/#{queue_url}" @@ -725,7 +725,7 @@ def bva_intake_return_to_caregiver(task, _user) modal_title: COPY::BVA_INTAKE_RETURN_TO_CAREGIVER_MODAL_TITLE, modal_body: COPY::BVA_INTAKE_RETURN_TO_CAREGIVER_MODAL_BODY, modal_button_text: COPY::MODAL_RETURN_BUTTON, - instructions_label: COPY::PRE_DOCKET_MODAL_BODY, + instructions_label: COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, message_title: format(COPY::BVA_INTAKE_RETURN_TO_CAREGIVER_CONFIRMATION_TITLE, task.appeal.veteran_full_name), type: VhaDocumentSearchTask.name, redirect_after: "/organizations/#{queue_url}" @@ -742,7 +742,7 @@ def bva_intake_return_to_emo(task, _user) modal_title: COPY::BVA_INTAKE_RETURN_TO_EMO_MODAL_TITLE, modal_body: COPY::BVA_INTAKE_RETURN_TO_EMO_MODAL_BODY, modal_button_text: COPY::MODAL_RETURN_BUTTON, - instructions_label: COPY::PRE_DOCKET_MODAL_BODY, + instructions_label: COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, message_title: format(COPY::BVA_INTAKE_RETURN_TO_EMO_CONFIRMATION_TITLE, task.appeal.veteran_full_name), type: EducationDocumentSearchTask.name, redirect_after: "/organizations/#{queue_url}" @@ -766,7 +766,7 @@ def emo_return_to_board_intake(*) { modal_title: COPY::EMO_RETURN_TO_BOARD_INTAKE_MODAL_TITLE, modal_button_text: COPY::MODAL_RETURN_BUTTON, - instructions_label: COPY::PRE_DOCKET_MODAL_BODY, + instructions_label: COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, type: EducationDocumentSearchTask.name, redirect_after: "/organizations/#{EducationEmo.singleton.url}" } @@ -778,7 +778,7 @@ def emo_assign_to_education_rpo_data(*) modal_title: COPY::EMO_ASSIGN_TO_RPO_MODAL_TITLE, modal_button_text: COPY::MODAL_ASSIGN_BUTTON, modal_selector_placeholder: COPY::EDUCATION_RPO_SELECTOR_PLACEHOLDER, - instructions_label: COPY::PRE_DOCKET_MODAL_BODY, + instructions_label: COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, drop_down_label: COPY::EMO_ASSIGN_TO_RPO_MODAL_BODY, type: EducationAssessDocumentationTask.name, redirect_after: "/organizations/#{EducationEmo.singleton.url}", @@ -795,7 +795,7 @@ def education_rpo_return_to_emo(task, _user) COPY::EDUCATION_RPO_RETURN_TO_EMO_CONFIRMATION, task.appeal.veteran_full_name ), - instructions_label: COPY::PRE_DOCKET_MODAL_BODY, + instructions_label: COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, type: EducationAssessDocumentationTask.name, redirect_after: "/organizations/#{queue_url}", modal_button_text: COPY::MODAL_RETURN_BUTTON diff --git a/client/COPY.json b/client/COPY.json index 29c03c8cf3b..b541dafa420 100644 --- a/client/COPY.json +++ b/client/COPY.json @@ -383,7 +383,6 @@ "MTV_CHECKOUT_RETURN_TO_JUDGE_ALERT_TITLE": "Prior decision issues marked for vacatur", "MTV_CHECKOUT_RETURN_TO_JUDGE_MODAL_TITLE": "Return to Judge", "MTV_CHECKOUT_RETURN_TO_JUDGE_MODAL_DESCRIPTION": "Use this action to return the Motion to Vacate task to your judge if you believe there is an error in the issues that have been marked for vacatur.\n\nIf your judge is unavailable, this will return to the Litigation Support team queue for reassignment.", - "MTV_CHECKOUT_RETURN_TO_JUDGE_MODAL_INSTRUCTIONS_LABEL": "Provide instructions and context for this action", "MTV_CHECKOUT_RETURN_TO_JUDGE_SUCCESS_TITLE": "%s's Motion to Vacate has been returned to %s", "MTV_CHECKOUT_RETURN_TO_JUDGE_SUCCESS_DETAILS": "If you made a mistake, please email your judge to resolve the issue.", @@ -597,7 +596,6 @@ "SCHEDULE_LATER_DISPLAY_TEXT": "Send to Schedule Veteran list", "ADD_COLOCATED_TASK_SUBHEAD": "Submit admin action", "ADD_COLOCATED_TASK_ACTION_TYPE_LABEL": "Select the type of administrative action you'd like to assign:", - "ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL": "Provide instructions and context for this action", "ADD_COLOCATED_TASK_ANOTHER_BUTTON_LABEL": "+ Add another action", "ADD_COLOCATED_TASK_REMOVE_BUTTON_LABEL": "Remove this action", "ADD_COLOCATED_TASK_SUBMIT_BUTTON_LABEL": "Assign Action", @@ -1215,7 +1213,6 @@ "VHA_ASSIGN_TO_REGIONAL_OFFICE_MODAL_TITLE": "Assign to VAMC/VISN", "VHA_ASSIGN_TO_REGIONAL_OFFICE_RADIO_LABEL": "Find the VISN by:", "VHA_ASSIGN_TO_REGIONAL_OFFICE_INSTRUCTIONS_LABEL": "Provide additional context for this action", - "PRE_DOCKET_MODAL_BODY": "Provide instructions and context for this action", "VHA_PROGRAM_OFFICE_SELECTOR_PLACEHOLDER": "Select Program Office", "VHA_REGIONAL_OFFICE_SELECTOR_PLACEHOLDER": "Select VISN/VA Medical Center", "VHA_COMPLETE_TASK_MODAL_TITLE": "Where were documents regarding this appeal stored?", diff --git a/client/app/queue/AssignToView.jsx b/client/app/queue/AssignToView.jsx index c50fa3b604a..34ef5f90089 100644 --- a/client/app/queue/AssignToView.jsx +++ b/client/app/queue/AssignToView.jsx @@ -344,7 +344,7 @@ class AssignToView extends React.Component { {!isPulacCerullo && (
{ } name={`${baseName}.instructions`} defaultValue={item.instructions} - label={ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL} + label={PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL} inputRef={register()} /> diff --git a/client/app/queue/colocatedTasks/AddColocatedTaskForm.jsx b/client/app/queue/colocatedTasks/AddColocatedTaskForm.jsx index e0e6e802c6f..237fa738490 100644 --- a/client/app/queue/colocatedTasks/AddColocatedTaskForm.jsx +++ b/client/app/queue/colocatedTasks/AddColocatedTaskForm.jsx @@ -40,7 +40,7 @@ export const AddColocatedTaskForm = ({ setInstructions(val)} value={instructions} /> diff --git a/client/app/queue/components/AssignToAttorneyWidget.jsx b/client/app/queue/components/AssignToAttorneyWidget.jsx index 479f1e129e1..cc8af42560c 100644 --- a/client/app/queue/components/AssignToAttorneyWidget.jsx +++ b/client/app/queue/components/AssignToAttorneyWidget.jsx @@ -257,7 +257,7 @@ export class AssignToAttorneyWidget extends React.PureComponent { {isModal &&
this.setState({ instructions: value })} diff --git a/client/app/queue/components/CancelTaskModal.jsx b/client/app/queue/components/CancelTaskModal.jsx index b9df49c9c0b..9db54ac73de 100644 --- a/client/app/queue/components/CancelTaskModal.jsx +++ b/client/app/queue/components/CancelTaskModal.jsx @@ -111,7 +111,7 @@ const CancelTaskModal = (props) => { } {get(taskData, 'show_instructions', true) && { } {shouldShowTaskInstructions && setInstructions(val)} value={instructions} diff --git a/client/test/app/queue/components/CancelTaskModal.test.js b/client/test/app/queue/components/CancelTaskModal.test.js index c463926b485..808e12d43fc 100644 --- a/client/test/app/queue/components/CancelTaskModal.test.js +++ b/client/test/app/queue/components/CancelTaskModal.test.js @@ -120,7 +120,7 @@ describe('Whenever RPO returns an appeal to EMO', () => { expect(screen.getByText(buttonText).closest('button')).toBeDisabled(); - enterTextFieldOptions(COPY.PRE_DOCKET_MODAL_BODY, additionalContextText); + enterTextFieldOptions(COPY.PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, additionalContextText); expect(screen.getByText(buttonText).closest('button')).not.toBeDisabled(); }); @@ -128,7 +128,7 @@ describe('Whenever RPO returns an appeal to EMO', () => { test('Resultant case timeline entry labels reason for cancellation', () => { renderCancelTaskModal(TASK_ACTIONS.EDUCATION_RPO_RETURN_TO_EMO.value, rpoToBvaIntakeData, taskType); - enterTextFieldOptions(COPY.PRE_DOCKET_MODAL_BODY, additionalContextText); + enterTextFieldOptions(COPY.PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, additionalContextText); clickSubmissionButton(buttonText); diff --git a/client/test/app/queue/components/CompleteTaskModal.test.js b/client/test/app/queue/components/CompleteTaskModal.test.js index 7277b02c330..db3d2b278db 100644 --- a/client/test/app/queue/components/CompleteTaskModal.test.js +++ b/client/test/app/queue/components/CompleteTaskModal.test.js @@ -639,7 +639,7 @@ describe('CompleteTaskModal', () => { expect(screen.getByText(buttonText).closest('button')).toBeDisabled(); enterTextFieldOptions( - COPY.PRE_DOCKET_MODAL_BODY, + COPY.PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, 'EMO Return to Board Intake' ); diff --git a/spec/feature/hearings/change_hearing_disposition_spec.rb b/spec/feature/hearings/change_hearing_disposition_spec.rb index 667d4883ceb..6bfe60cb900 100644 --- a/spec/feature/hearings/change_hearing_disposition_spec.rb +++ b/spec/feature/hearings/change_hearing_disposition_spec.rb @@ -406,7 +406,7 @@ expect(choices).to include(*admin_full_names) expect(choices).to_not include(*mgmt_full_names) - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: assign_instructions_text + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: assign_instructions_text click_on "Submit" expect(page).to have_content COPY::REASSIGN_TASK_SUCCESS_MESSAGE % other_admin_full_name end @@ -435,7 +435,7 @@ step "assign the task to self" do click_dropdown(prompt: "Select an action", text: "Assign to person") - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: assign_instructions_text + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: assign_instructions_text click_on "Submit" expect(page).to have_content COPY::REASSIGN_TASK_SUCCESS_MESSAGE % current_full_name end diff --git a/spec/feature/hearings/schedule_veteran/build_hearsched_spec.rb b/spec/feature/hearings/schedule_veteran/build_hearsched_spec.rb index 69a05dcdb64..dbab112e97f 100644 --- a/spec/feature/hearings/schedule_veteran/build_hearsched_spec.rb +++ b/spec/feature/hearings/schedule_veteran/build_hearsched_spec.rb @@ -519,13 +519,13 @@ def format_hearing_day(hearing_day, detail_label = nil, total_slots = 0) # First admin action expect(page).to have_content("Submit admin action") click_dropdown(text: HearingAdminActionIncarceratedVeteranTask.label) - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: incarcerated_veteran_task_instructions + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: incarcerated_veteran_task_instructions # Second admin action click_on COPY::ADD_COLOCATED_TASK_ANOTHER_BUTTON_LABEL within all('div[id^="action_"]', count: 2)[1] do click_dropdown(text: HearingAdminActionContestedClaimantTask.label) - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: contested_claimant_task_instructions + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: contested_claimant_task_instructions end click_on "Assign Action" @@ -572,7 +572,7 @@ def format_hearing_day(hearing_day, detail_label = nil, total_slots = 0) end click_dropdown({ text: other_user.full_name }, find(".cf-modal-body")) - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: "Reassign" + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: "Reassign" click_on "Submit" # Case should exist in other users' queue @@ -599,7 +599,7 @@ def format_hearing_day(hearing_day, detail_label = nil, total_slots = 0) # First admin action expect(page).to have_content("Submit admin action") click_dropdown(text: HearingAdminActionIncarceratedVeteranTask.label) - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: "Action 1" + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: "Action 1" click_on "Assign Action" expect(page).to have_content("You have assigned an administrative action") diff --git a/spec/feature/queue/ama_queue_spec.rb b/spec/feature/queue/ama_queue_spec.rb index 2fb40a56ff7..2fc1e42826a 100644 --- a/spec/feature/queue/ama_queue_spec.rb +++ b/spec/feature/queue/ama_queue_spec.rb @@ -462,7 +462,7 @@ def judge_assign_to_attorney click_dropdown(prompt: "Select an action", text: "Assign to attorney") click_dropdown(prompt: "Select a user", text: attorney_user.full_name) - fill_in(COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: "note") + fill_in(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: "note") click_on "Submit" @@ -776,7 +776,7 @@ def judge_assign_to_attorney click_dropdown(prompt: "Select an action", text: "Assign to attorney") click_dropdown(prompt: "Select a user", text: attorney_user.full_name) - fill_in(COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: "note") + fill_in(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: "note") click_on "Submit" diff --git a/spec/feature/queue/case_assignment_spec.rb b/spec/feature/queue/case_assignment_spec.rb index 72cc3aee448..35d71ec7ab3 100644 --- a/spec/feature/queue/case_assignment_spec.rb +++ b/spec/feature/queue/case_assignment_spec.rb @@ -48,7 +48,7 @@ expect(visible_options.length).to eq Constants::CO_LOCATED_ADMIN_ACTIONS.length end - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: instructions + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: instructions click_on COPY::ADD_COLOCATED_TASK_ANOTHER_BUTTON_LABEL @@ -56,7 +56,7 @@ within all('div[id^="action_"]')[1] do click_dropdown(text: selected_opt_0) - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: instructions + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: instructions end click_on COPY::ADD_COLOCATED_TASK_SUBMIT_BUTTON_LABEL @@ -90,7 +90,7 @@ selected_opt_1 = Constants::CO_LOCATED_ADMIN_ACTIONS[action] click_dropdown(text: selected_opt_1) - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: generate_words(4) + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: generate_words(4) # step "adds another admin action" click_on COPY::ADD_COLOCATED_TASK_ANOTHER_BUTTON_LABEL @@ -102,7 +102,7 @@ within all('div[id^="action_"]')[1] do click_dropdown(text: selected_opt_2) - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: generate_words(5) + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: generate_words(5) end # step "adds a third admin action with no instructions" @@ -132,7 +132,7 @@ expect(page).to have_content COPY::INSTRUCTIONS_ERROR_FIELD_REQUIRED within all('div[id^="action_"]')[1] do - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: generate_words(4) + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: generate_words(4) end # step "submits two admin actions" diff --git a/spec/feature/queue/colocated_task_queue_spec.rb b/spec/feature/queue/colocated_task_queue_spec.rb index 88a5af39375..ae97ebe03a9 100644 --- a/spec/feature/queue/colocated_task_queue_spec.rb +++ b/spec/feature/queue/colocated_task_queue_spec.rb @@ -39,7 +39,7 @@ action = Constants.CO_LOCATED_ADMIN_ACTIONS.poa_clarification find(".cf-select__control", text: "Select an action").click find("div", class: "cf-select__option", text: action).click - fill_in(COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: "note") + fill_in(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: "note") find("button", text: COPY::ADD_COLOCATED_TASK_SUBMIT_BUTTON_LABEL).click # Redirected to personal queue page. Assignment succeeds. diff --git a/spec/feature/queue/docket_switch_spec.rb b/spec/feature/queue/docket_switch_spec.rb index e160cb3c5aa..7f1ce0ccfdf 100644 --- a/spec/feature/queue/docket_switch_spec.rb +++ b/spec/feature/queue/docket_switch_spec.rb @@ -585,7 +585,7 @@ expect(visible_options.length).to eq Constants::CO_LOCATED_ADMIN_ACTIONS.length end - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: admin_action_instructions + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: admin_action_instructions expect(page).to have_button("Continue", disabled: false) click_button(text: "Continue") diff --git a/spec/feature/queue/judge_assignment_spec.rb b/spec/feature/queue/judge_assignment_spec.rb index cc227bcc6f0..a1d131b368b 100644 --- a/spec/feature/queue/judge_assignment_spec.rb +++ b/spec/feature/queue/judge_assignment_spec.rb @@ -285,7 +285,7 @@ click_dropdown(text: Constants.TASK_ACTIONS.ASSIGN_TO_ATTORNEY.label) click_dropdown(prompt: "Select a user", text: attorney_one.full_name) - fill_in(COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: "note") + fill_in(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: "note") click_on("Submit") expect(page).to have_content("Assigned 1 task to #{attorney_one.full_name}") @@ -334,7 +334,7 @@ click_dropdown(prompt: "Select a user", text: "Other") safe_click ".dropdown-Other" click_dropdown({ text: judge_two.full_name }, page.find(".dropdown-Other")) - fill_in(COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: "note") + fill_in(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: "note") click_on("Submit") expect(page).to have_content("Assigned 1 task to #{judge_two.full_name}") @@ -351,7 +351,7 @@ click_dropdown(text: Constants.TASK_ACTIONS.ASSIGN_TO_ATTORNEY.label) click_dropdown(prompt: "Select a user", text: judge_one.full_name) - fill_in(COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: "note") + fill_in(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: "note") click_on("Submit") expect(page).to have_content("Assigned 1 task to #{judge_one.full_name}") diff --git a/spec/feature/queue/motion_to_vacate_spec.rb b/spec/feature/queue/motion_to_vacate_spec.rb index 1841031eaf7..216e70dad77 100644 --- a/spec/feature/queue/motion_to_vacate_spec.rb +++ b/spec/feature/queue/motion_to_vacate_spec.rb @@ -977,7 +977,7 @@ def add_decision_to_issue(idx, disposition, description) expect(visible_options.length).to eq Constants::CO_LOCATED_ADMIN_ACTIONS.length end - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: instructions + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: instructions click_on COPY::ADD_COLOCATED_TASK_ANOTHER_BUTTON_LABEL @@ -985,7 +985,7 @@ def add_decision_to_issue(idx, disposition, description) within all("div.admin-action-item")[1] do click_dropdown(text: selected_opt_0) - fill_in COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: instructions + fill_in COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: instructions end expect(page).to have_content("Duplicate admin actions detected") diff --git a/spec/feature/queue/pre_docket_spec.rb b/spec/feature/queue/pre_docket_spec.rb index 278122aa539..d11d03e1d9a 100644 --- a/spec/feature/queue/pre_docket_spec.rb +++ b/spec/feature/queue/pre_docket_spec.rb @@ -399,10 +399,10 @@ find(".cf-select__control", text: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL).click find("div", class: "cf-select__option", text: Constants.TASK_ACTIONS.VHA_ASSIGN_TO_PROGRAM_OFFICE.label).click expect(page).to have_content(COPY::VHA_ASSIGN_TO_PROGRAM_OFFICE_MODAL_TITLE) - expect(page).to have_content(COPY::PRE_DOCKET_MODAL_BODY) + expect(page).to have_content(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL) find(".cf-select__control", text: COPY::VHA_PROGRAM_OFFICE_SELECTOR_PLACEHOLDER).click find("div", class: "cf-select__option", text: program_office.name).click - fill_in(COPY::PRE_DOCKET_MODAL_BODY, with: po_instructions) + fill_in(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: po_instructions) find("button", class: "usa-button", text: COPY::MODAL_ASSIGN_BUTTON).click expect(page).to have_current_path("/organizations/#{camo.url}?tab=camo_assigned&#{default_query_params}") @@ -904,7 +904,7 @@ def bva_intake_dockets_appeal text: Constants.TASK_ACTIONS.EMO_ASSIGN_TO_RPO.label ).click expect(page).to have_content(COPY::EMO_ASSIGN_TO_RPO_MODAL_TITLE) - expect(page).to have_content(COPY::PRE_DOCKET_MODAL_BODY) + expect(page).to have_content(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL) find(".cf-select__control", text: COPY::EDUCATION_RPO_SELECTOR_PLACEHOLDER).click find("div", class: "cf-select__option", text: education_rpo.name).click @@ -1045,7 +1045,7 @@ def bva_intake_dockets_appeal find(class: "cf-select__control", text: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL).click find("div", class: "cf-select__option", text: Constants.TASK_ACTIONS.EMO_RETURN_TO_BOARD_INTAKE.label).click expect(page).to have_content(COPY::EMO_RETURN_TO_BOARD_INTAKE_MODAL_TITLE) - expect(page).to have_content(COPY::PRE_DOCKET_MODAL_BODY) + expect(page).to have_content(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL) end step "If no text is entered into the modal's textarea it prevents submission" do @@ -1120,7 +1120,7 @@ def bva_intake_dockets_appeal ).click expect(page).to have_content(COPY::EDUCATION_RPO_RETURN_TO_EMO_MODAL_TITLE) - expect(page).to have_content(COPY::PRE_DOCKET_MODAL_BODY) + expect(page).to have_content(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL) submit_button = find("button", text: COPY::MODAL_RETURN_BUTTON) expect(submit_button[:disabled]).to eq "true" diff --git a/spec/feature/queue/scm_judge_assignment_spec.rb b/spec/feature/queue/scm_judge_assignment_spec.rb index b34110f01eb..671015fa739 100644 --- a/spec/feature/queue/scm_judge_assignment_spec.rb +++ b/spec/feature/queue/scm_judge_assignment_spec.rb @@ -160,7 +160,7 @@ click_dropdown(prompt: "Select a user", text: "Other") click_dropdown(prompt: "Select a user", text: attorney_one.full_name) instructions = "#{judge_one.full_name} is on leave. Please draft a decision for this case" - fill_in(COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: instructions) + fill_in(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: instructions) click_on("Submit") expect(page).to have_content("Assigned 1 task to #{attorney_one.full_name}") @@ -250,7 +250,7 @@ click_dropdown(prompt: "Select a user", text: "Other") click_dropdown(prompt: "Select a user", text: attorney_one.full_name) instructions = "#{judge_one.full_name} is on leave. Please draft a decision for this case" - fill_in(COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: instructions) + fill_in(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: instructions) click_on("Submit") expect(page).to have_content("Assigned 1 task to #{attorney_one.full_name}") diff --git a/spec/feature/queue/task_queue_spec.rb b/spec/feature/queue/task_queue_spec.rb index 9fe3a6321c6..e27cbc901d9 100644 --- a/spec/feature/queue/task_queue_spec.rb +++ b/spec/feature/queue/task_queue_spec.rb @@ -825,7 +825,7 @@ def validate_pulac_cerullo_tasks_created(task_class, label) # On case details page fill in the admin action action = Constants.CO_LOCATED_ADMIN_ACTIONS.ihp click_dropdown(text: action) - fill_in(COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: "Please complete this task") + fill_in(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: "Please complete this task") find("button", text: COPY::ADD_COLOCATED_TASK_SUBMIT_BUTTON_LABEL).click # Expect to see a success message, the correct number of remaining tasks and have the task in the database @@ -1069,7 +1069,7 @@ def validate_pulac_cerullo_tasks_created(task_class, label) # On case details page fill in the admin action action = Constants.CO_LOCATED_ADMIN_ACTIONS.ihp click_dropdown(text: action) - fill_in(COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: "Please complete this task") + fill_in(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: "Please complete this task") find("button", text: COPY::ADD_COLOCATED_TASK_SUBMIT_BUTTON_LABEL).click # Expect to see a success message and the correct number of remaining tasks diff --git a/spec/fixes/investigate_scm_cant_reassign_spec.rb b/spec/fixes/investigate_scm_cant_reassign_spec.rb index a55e469c74d..e7d9223a8bd 100644 --- a/spec/fixes/investigate_scm_cant_reassign_spec.rb +++ b/spec/fixes/investigate_scm_cant_reassign_spec.rb @@ -33,7 +33,7 @@ # Clicking on "Other" and starting to type "TALAM" shows the attorney. click_dropdown(prompt: "Select a user", text: attorney_user.full_name) - fill_in(COPY::ADD_COLOCATED_TASK_INSTRUCTIONS_LABEL, with: "\nSCM user reassigning to different attorney") + fill_in(COPY::PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, with: "\nSCM user reassigning to different attorney") # Clicking Submit button shows an "Error assigning tasks" error banner in the modal # (and an error message in the DevTools console). From 4b85c8b5cc49bd9191a8eb0f2406e84283fc78a1 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Thu, 3 Aug 2023 12:36:08 -0400 Subject: [PATCH 43/87] refactored all 'Provide context and instructions' copy across caseflow to 'Provide instructions and context' --- client/COPY.json | 2 -- client/app/queue/cavc/AddCavcDatesModal.jsx | 2 +- client/app/queue/cavc/AddCavcRemandView.jsx | 2 +- client/app/queue/cavc/EditCavcRemandForm.jsx | 4 ++-- .../app/queue/components/CavcReviewExtensionRequestModal.jsx | 2 +- client/app/queue/mtv/ReturnToLitSupportModal.jsx | 4 ++-- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/client/COPY.json b/client/COPY.json index b541dafa420..2fd210129c1 100644 --- a/client/COPY.json +++ b/client/COPY.json @@ -208,7 +208,6 @@ "CAVC_ALL_ISSUES_ERROR": "Please select all issues to proceed", "CAVC_FEDERAL_CIRCUIT_HEADER": "Notice of Appeal to the Federal Circuit", "CAVC_FEDERAL_CIRCUIT_LABEL": "Yes, this case has been appealed to the Federal Circuit", - "CAVC_INSTRUCTIONS_LABEL": "Provide context and instructions for this action", "CAVC_INSTRUCTIONS_ERROR": "Please provide context and instructions for the remand", "CAVC_REMAND_CREATED_TITLE": "You have successfully created a CAVC remand case", "CAVC_DASHBOARD_ENTRY_CREATED_TITLE": "You have successfully created an entry in the CAVC dashboard", @@ -360,7 +359,6 @@ "JUDGE_ADDRESS_MTV_SUCCESS_DETAIL_DENIED": "This task will be completed by the original motions attorney or placed in the team's queue", "RETURN_TO_LIT_SUPPORT_MODAL_TITLE": "Return to Litigation Support", "RETURN_TO_LIT_SUPPORT_MODAL_CONTENT": "Use this action to return the Motion to Vacate task to the previous Motions Attorney in order to request changes to the ruling letter draft, or if the ruling letter draft is missing.\n\nIf the previous attorney is inactive, this will return to the Litigation Support team queue for reassignment.", - "RETURN_TO_LIT_SUPPORT_MODAL_INSTRUCTIONS_LABEL": "Provide context and instructions for this action", "RETURN_TO_LIT_SUPPORT_MODAL_DEFAULT_INSTRUCTIONS": "I am missing a link to the draft ruling letter. Please resubmit so I can review and sign.", "RETURN_TO_LIT_SUPPORT_SUCCESS_TITLE": "%s's Motion to Vacate has been returned to Litigation Support", "RETURN_TO_LIT_SUPPORT_SUCCESS_DETAIL": "This task will be completed by the original Motions Attorney or placed in the team's queue", diff --git a/client/app/queue/cavc/AddCavcDatesModal.jsx b/client/app/queue/cavc/AddCavcDatesModal.jsx index ebe1c45991f..1bf8edeef58 100644 --- a/client/app/queue/cavc/AddCavcDatesModal.jsx +++ b/client/app/queue/cavc/AddCavcDatesModal.jsx @@ -93,7 +93,7 @@ const AddCavcDatesModal = ({ appealId, decisionType, error, highlightInvalid, hi />; const instructionsTextField = setInstructions(val)} diff --git a/client/app/queue/cavc/AddCavcRemandView.jsx b/client/app/queue/cavc/AddCavcRemandView.jsx index 95ba940028f..a7d8655590e 100644 --- a/client/app/queue/cavc/AddCavcRemandView.jsx +++ b/client/app/queue/cavc/AddCavcRemandView.jsx @@ -516,7 +516,7 @@ const AddCavcRemandView = (props) => {
; const instructionsField = setInstructions(val)} diff --git a/client/app/queue/cavc/EditCavcRemandForm.jsx b/client/app/queue/cavc/EditCavcRemandForm.jsx index 2ff92a566cf..4cfd3d85a0b 100644 --- a/client/app/queue/cavc/EditCavcRemandForm.jsx +++ b/client/app/queue/cavc/EditCavcRemandForm.jsx @@ -11,7 +11,7 @@ import AppSegment from '@department-of-veterans-affairs/caseflow-frontend-toolki import { ADD_CAVC_PAGE_TITLE, CAVC_ATTORNEY_LABEL, CAVC_COURT_DECISION_DATE, CAVC_DOCKET_NUMBER_LABEL, CAVC_DOCKET_NUMBER_ERROR, CAVC_FEDERAL_CIRCUIT_HEADER, CAVC_FEDERAL_CIRCUIT_LABEL, CAVC_JUDGE_ERROR, CAVC_JUDGE_LABEL, - CAVC_JUDGEMENT_DATE, CAVC_INSTRUCTIONS_ERROR, CAVC_INSTRUCTIONS_LABEL, CAVC_ISSUES_LABEL, + CAVC_JUDGEMENT_DATE, CAVC_INSTRUCTIONS_ERROR, PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL, CAVC_ISSUES_LABEL, CAVC_MANDATE_DATE, CAVC_REMAND_MANDATE_DATES_LABEL, CAVC_REMAND_MANDATE_QUESTION, CAVC_REMAND_MANDATE_DATES_SAME_DESCRIPTION, CAVC_SUB_TYPE_LABEL, CAVC_TYPE_LABEL, EDIT_CAVC_PAGE_TITLE, CAVC_SUBSTITUTE_APPELLANT_LABEL, CAVC_SUBSTITUTE_APPELLANT_DATE_LABEL, @@ -454,7 +454,7 @@ export const EditCavcRemandForm = ({ setInstructions(val)} value={instructions} className={['mtv-decision-instructions']} From bc39b17570bc734a82aa255de16c5c03f99107ae Mon Sep 17 00:00:00 2001 From: Minhazur Rahaman Date: Thu, 3 Aug 2023 14:25:16 -0400 Subject: [PATCH 44/87] APPEALS-25000 changed enabled submit colors and restricted task from changing to itself from UI --- app/repositories/task_action_repository.rb | 1 + client/app/queue/AssignToView.jsx | 3 ++- client/app/queue/ChangeTaskTypeModal.jsx | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/repositories/task_action_repository.rb b/app/repositories/task_action_repository.rb index e81e2085bed..7a43a474107 100644 --- a/app/repositories/task_action_repository.rb +++ b/app/repositories/task_action_repository.rb @@ -19,6 +19,7 @@ def assign_to_organization_data(task, _user = nil) def mail_assign_to_organization_data(task, user = nil) options = MailTask.descendant_routing_options(user: user, appeal: task.appeal) + .reject { |opt| opt[:value] == task.type } valid_options = task.appeal.outcoded? ? options : options.reject { |opt| opt[:value] == "VacateMotionMailTask" } { options: valid_options } end diff --git a/client/app/queue/AssignToView.jsx b/client/app/queue/AssignToView.jsx index c50fa3b604a..56fdcb84a96 100644 --- a/client/app/queue/AssignToView.jsx +++ b/client/app/queue/AssignToView.jsx @@ -297,7 +297,8 @@ class AssignToView extends React.Component { 'PreDocketTask', 'VhaDocumentSearchTask', 'EducationDocumentSearchTask', - 'AssessDocumentationTask' + 'AssessDocumentationTask', + 'HearingPostponementRequestMailTask' ].includes(task.type)) { modalProps.submitDisabled = !this.validateForm(); modalProps.submitButtonClassNames = ['usa-button']; diff --git a/client/app/queue/ChangeTaskTypeModal.jsx b/client/app/queue/ChangeTaskTypeModal.jsx index 61d6bc1a33c..9711b0e443f 100644 --- a/client/app/queue/ChangeTaskTypeModal.jsx +++ b/client/app/queue/ChangeTaskTypeModal.jsx @@ -103,6 +103,7 @@ class ChangeTaskTypeModal extends React.PureComponent { title={COPY.CHANGE_TASK_TYPE_SUBHEAD} button={COPY.CHANGE_TASK_TYPE_SUBHEAD} pathAfterSubmit={`/queue/appeals/${this.props.appealId}`} + submitButtonClassNames={['usa-button']} > {error && {error.detail} From c47991509c09bd830cb5dbefc290d68366583de8 Mon Sep 17 00:00:00 2001 From: Minhazur Rahaman Date: Thu, 3 Aug 2023 16:15:36 -0400 Subject: [PATCH 45/87] APPEALS-25000 changed submit button colors when enabled --- client/app/queue/components/CancelTaskModal.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/app/queue/components/CancelTaskModal.jsx b/client/app/queue/components/CancelTaskModal.jsx index b9df49c9c0b..09d9bc97178 100644 --- a/client/app/queue/components/CancelTaskModal.jsx +++ b/client/app/queue/components/CancelTaskModal.jsx @@ -85,6 +85,7 @@ const CancelTaskModal = (props) => { if ([ 'AssessDocumentationTask', 'EducationAssessDocumentationTask', + 'HearingPostponementRequestMailTask' ].includes(task?.type)) { modalProps.submitButtonClassNames = ['usa-button']; modalProps.submitDisabled = !validateForm(); From ede92a35bcc60fee3d1ee3ee8e4ba0eea2a3bba8 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Thu, 3 Aug 2023 16:30:31 -0400 Subject: [PATCH 46/87] APPEALS-24997 fixed bug in form validation --- .../CompleteHearingPostponementRequestModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index c3c6684660a..11813378148 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -73,7 +73,7 @@ const CompleteHearingPostponementRequestModal = (props) => { const { granted, rulingDate, instructions, scheduledOption } = state; if (granted) { - return rulingDate.valid && instructions !== '' && scheduledOption !== ''; + return rulingDate.valid && instructions !== '' && scheduledOption !== null; } return granted !== null && rulingDate.valid && instructions !== ''; From 1b233bc5fdda7a16892dda21bce62e1fd3f2da78 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Fri, 4 Aug 2023 00:12:25 -0400 Subject: [PATCH 47/87] APPEALS-24997 refactored event sequences in test and date UTC issue --- client/test/app/jestSetup.js | 2 +- ...eteHearingPostponementRequestModal.test.js | 120 ++++++++---------- 2 files changed, 57 insertions(+), 65 deletions(-) diff --git a/client/test/app/jestSetup.js b/client/test/app/jestSetup.js index e8fb9d3cc41..3a3e60f15ca 100644 --- a/client/test/app/jestSetup.js +++ b/client/test/app/jestSetup.js @@ -13,7 +13,7 @@ global.scrollTo = jest.fn(); // Spy to ignore console warnings jest.spyOn(console, 'warn').mockReturnValue(); -jest.spyOn(console, 'log').mockReturnValue(); +// jest.spyOn(console, 'log').mockReturnValue(); jest.spyOn(console, 'error').mockReturnValue(); // Mock the Date generated for all tests diff --git a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js index 48cbed1d0f2..37068f98504 100644 --- a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js +++ b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js @@ -48,14 +48,19 @@ describe('CompleteHearingPostponementRequestModal', () => { const [reschedule, scheduleLater] = ['Reschedule immediately', 'Send to Schedule Veteran list']; const instructions = `${COPY.PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL}:`; - const rescheduleBtn = () => screen.queryByRole('radio', { name: reschedule }); - const scheduleLaterBtn = () => screen.queryByRole('radio', { name: scheduleLater }); - const instructionsTextArea = () => screen.getByRole('textbox', { name: instructions }); - const submitButton = () => screen.getByRole('button', { name: modalAction }); + const fields = { + granted: () => screen.getByRole('radio', { name: granted }), + denied: () => screen.getByRole('radio', { name: denied }), + reschedule: () => screen.queryByRole('radio', { name: reschedule }), + scheduleLater: () => screen.queryByRole('radio', { name: scheduleLater }), + date: () => screen.getByLabelText(datePrompt), + instructions: () => screen.getByRole('textbox', { name: instructions }), + submit: () => screen.getByRole('button', { name: modalAction }) + }; const formatDate = (date) => format(date, 'yyyy-MM-dd').toString(); const today = formatDate(new Date()); - const tomorrow = formatDate(add(new Date(), { days: 1 })); + const tomorrow = formatDate(add(new Date(), { days: 2 })); describe('on modal open', () => { test('modal title: "Mark as complete"', () => { @@ -77,8 +82,8 @@ describe('CompleteHearingPostponementRequestModal', () => { renderCompleteHprModal(completeHearingPostponementRequestData); expect(screen.getAllByRole('radio')).toHaveLength(2); - expect(screen.getByRole('radio', { name: granted })).toBeInTheDocument(); - expect(screen.getByRole('radio', { name: denied })).toBeInTheDocument(); + expect(fields.granted()).toBeInTheDocument(); + expect(fields.denied()).toBeInTheDocument(); }); }); @@ -86,7 +91,7 @@ describe('CompleteHearingPostponementRequestModal', () => { test('has date input with text prompt "Date of ruling:"', () => { renderCompleteHprModal(completeHearingPostponementRequestData); - expect(screen.getByLabelText(datePrompt)).toBeInTheDocument(); + expect(fields.date()).toBeInTheDocument(); }); }); @@ -94,7 +99,7 @@ describe('CompleteHearingPostponementRequestModal', () => { test('has text prompt "Provide instructions and context for this action:"', () => { renderCompleteHprModal(completeHearingPostponementRequestData); - expect(instructionsTextArea()).toBeInTheDocument(); + expect(fields.instructions()).toBeInTheDocument(); }); }); @@ -102,8 +107,8 @@ describe('CompleteHearingPostponementRequestModal', () => { test('are not present', () => { renderCompleteHprModal(completeHearingPostponementRequestData); - expect(rescheduleBtn()).not.toBeInTheDocument(); - expect(scheduleLaterBtn()).not.toBeInTheDocument(); + expect(screen.queryByRole('radio', { name: reschedule })).not.toBeInTheDocument(); + expect(screen.queryByRole('radio', { name: scheduleLater })).not.toBeInTheDocument(); }); }); @@ -111,7 +116,7 @@ describe('CompleteHearingPostponementRequestModal', () => { test('submit button is initially disabled', () => { renderCompleteHprModal(completeHearingPostponementRequestData); - expect(submitButton()).toBeDisabled(); + expect(fields.submit()).toBeDisabled(); }); }); }); @@ -122,8 +127,8 @@ describe('CompleteHearingPostponementRequestModal', () => { renderCompleteHprModal(completeHearingPostponementRequestData); enterModalRadioOptions(granted); - expect(rescheduleBtn()).toBeInTheDocument(); - expect(scheduleLaterBtn()).toBeInTheDocument(); + expect(fields.reschedule()).toBeInTheDocument(); + expect(fields.scheduleLater()).toBeInTheDocument(); }); }); @@ -132,8 +137,8 @@ describe('CompleteHearingPostponementRequestModal', () => { renderCompleteHprModal(completeHearingPostponementRequestData); enterModalRadioOptions(denied); - expect(rescheduleBtn()).not.toBeInTheDocument(); - expect(scheduleLaterBtn()).not.toBeInTheDocument(); + expect(screen.queryByRole('radio', { name: reschedule })).not.toBeInTheDocument(); + expect(screen.queryByRole('radio', { name: scheduleLater })).not.toBeInTheDocument(); }); }); }); @@ -161,12 +166,16 @@ describe('CompleteHearingPostponementRequestModal', () => { }); describe('on validate form', () => { - const completeValidForm = (eventSequence) => { - for (const event in eventSequence) { - if (eventSequence[event]) { - eventSequence[event].call(); - } - } + const modalEvents = { + granted: () => enterModalRadioOptions(granted), + denied: () => enterModalRadioOptions(denied), + date: () => enterInputValue(datePrompt, today), + reschedule: () => enterModalRadioOptions(reschedule), + instructions: () => enterTextFieldOptions(instructions, 'test') + }; + + const completeForm = (eventSequence) => { + eventSequence.forEach((event) => modalEvents[event].call()); }; const testValidForm = (eventSequence) => { @@ -174,64 +183,47 @@ describe('CompleteHearingPostponementRequestModal', () => { test('submit button is enabled', () => { renderCompleteHprModal(completeHearingPostponementRequestData); - completeValidForm(eventSequence); - expect(submitButton()).not.toBeDisabled(); + completeForm(eventSequence); + expect(fields.submit()).not.toBeDisabled(); }); }); }; - const completeInvalidForm = (eventSequence, invalidEvent) => { - for (const event in eventSequence) { - if ( - eventSequence[event] && - event !== invalidEvent && - (invalidEvent === 'granted' && event !== 'reschedule') - ) { - eventSequence[event].call(); - } - } - }; - - const runInvalidationTestOnEachField = (eventSequence) => { - Object.keys(eventSequence).forEach((key) => { - describe(`${key} field is invalid`, () => { + const runInvalidationTestOnEachField = (eventSequences) => { + describe('any field is invalid', () => { + describe.each(eventSequences)('$invalidField field is invalid', (invalidField, eventSequence) => { test('submit button is disabled', () => { renderCompleteHprModal(completeHearingPostponementRequestData); - completeInvalidForm(eventSequence, key); - expect(submitButton()).toBeDisabled(); + completeForm(eventSequence); + expect(fields[invalidField].call()).toBeInTheDocument(); + expect(fields.submit()).toBeDisabled(); }); }); }); }; describe('judge ruling is "Granted"', () => { - const validModalEvents = { - granted: () => enterModalRadioOptions(granted), - date: () => enterInputValue(datePrompt, today), - reschedule: () => enterModalRadioOptions(reschedule), - instructions: () => enterTextFieldOptions(instructions, 'test') - }; - - testValidForm(validModalEvents); - - describe('any field is invalid', () => { - runInvalidationTestOnEachField(validModalEvents); - }); + const eventSequences = [ + ['granted', ['date', 'instructions']], + ['date', ['granted', 'reschedule', 'instructions']], + ['reschedule', ['granted', 'date', 'instructions']], + ['instructions', ['granted', 'date', 'reschedule']] + ]; + + testValidForm(['granted', 'date', 'reschedule', 'instructions']); + runInvalidationTestOnEachField(eventSequences); }); describe('judge ruling is "Denied"', () => { - const validModalEvents = { - denied: () => enterModalRadioOptions(denied), - date: () => enterInputValue(datePrompt, today), - instructions: () => enterTextFieldOptions(instructions, 'test') - }; - - testValidForm(validModalEvents); - - describe('any field is invalid', () => { - runInvalidationTestOnEachField(validModalEvents); - }); + const eventSequences = [ + ['denied', ['date', 'instructions']], + ['date', ['denied', 'instructions']], + ['instructions', ['denied', 'date']] + ]; + + testValidForm(['denied', 'date', 'instructions']); + runInvalidationTestOnEachField(eventSequences); }); }); }); From 6ce41ddf764fc5286b240e62257c7c100897644b Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Fri, 4 Aug 2023 00:28:32 -0400 Subject: [PATCH 48/87] APPEALS-24997 changed tomorrow to futureDate --- .../CompleteHearingPostponementRequestModal.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js index 37068f98504..d00840b5ad5 100644 --- a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js +++ b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js @@ -60,7 +60,7 @@ describe('CompleteHearingPostponementRequestModal', () => { const formatDate = (date) => format(date, 'yyyy-MM-dd').toString(); const today = formatDate(new Date()); - const tomorrow = formatDate(add(new Date(), { days: 2 })); + const futureDate = formatDate(add(new Date(), { days: 2 })); describe('on modal open', () => { test('modal title: "Mark as complete"', () => { @@ -150,7 +150,7 @@ describe('CompleteHearingPostponementRequestModal', () => { test('date error message appears', () => { renderCompleteHprModal(completeHearingPostponementRequestData); - enterInputValue(datePrompt, tomorrow); + enterInputValue(datePrompt, futureDate); expect(screen.getByText(dateErrorMessage)).toBeInTheDocument(); }); }); From c6c375efa3a36946acf8888496b3f3c3bc6f5aa9 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Fri, 4 Aug 2023 00:39:07 -0400 Subject: [PATCH 49/87] APPEALS-24997 uncommented jestsetup and fixed describe name in test --- client/test/app/jestSetup.js | 2 +- .../CompleteHearingPostponementRequestModal.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/test/app/jestSetup.js b/client/test/app/jestSetup.js index 3a3e60f15ca..e8fb9d3cc41 100644 --- a/client/test/app/jestSetup.js +++ b/client/test/app/jestSetup.js @@ -13,7 +13,7 @@ global.scrollTo = jest.fn(); // Spy to ignore console warnings jest.spyOn(console, 'warn').mockReturnValue(); -// jest.spyOn(console, 'log').mockReturnValue(); +jest.spyOn(console, 'log').mockReturnValue(); jest.spyOn(console, 'error').mockReturnValue(); // Mock the Date generated for all tests diff --git a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js index d00840b5ad5..011ec77392d 100644 --- a/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js +++ b/client/test/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.test.js @@ -191,7 +191,7 @@ describe('CompleteHearingPostponementRequestModal', () => { const runInvalidationTestOnEachField = (eventSequences) => { describe('any field is invalid', () => { - describe.each(eventSequences)('$invalidField field is invalid', (invalidField, eventSequence) => { + describe.each(eventSequences)('%s field is invalid', (invalidField, eventSequence) => { test('submit button is disabled', () => { renderCompleteHprModal(completeHearingPostponementRequestData); From 8886c94f1deb30b8c04f17cf95a4eaf2432a7992 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Fri, 4 Aug 2023 11:56:20 -0400 Subject: [PATCH 50/87] APPEALS-24997 fixed missing controlled form --- .../CompleteHearingPostponementRequestModal.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index 11813378148..bc6e6c71c54 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -53,7 +53,7 @@ const CompleteHearingPostponementRequestModal = (props) => { return { ...state, scheduledOption: action.payload - } + }; default: throw new Error('Unknown action type'); } @@ -137,6 +137,7 @@ const CompleteHearingPostponementRequestModal = (props) => { name="instructionsField" id="completePostponementInstructions" onChange={(value) => dispatch({ type: 'instructions', payload: value })} + value={state.instructions} styling={marginBottom(0)} /> From ea59c717f37ee0456ec6c5d5bff91bcacdee04f7 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Fri, 4 Aug 2023 16:04:04 -0400 Subject: [PATCH 51/87] APPEALS-24997 fixed linting in QueueApp --- client/app/queue/QueueApp.jsx | 60 +++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/client/app/queue/QueueApp.jsx b/client/app/queue/QueueApp.jsx index c30a9fea620..ab0841fe950 100644 --- a/client/app/queue/QueueApp.jsx +++ b/client/app/queue/QueueApp.jsx @@ -760,15 +760,15 @@ class QueueApp extends React.PureComponent { // eslint-disable-next-line default-case switch (this.props.reviewActionType) { - case DECISION_TYPES.OMO_REQUEST: - reviewActionType = 'OMO'; - break; - case DECISION_TYPES.DRAFT_DECISION: - reviewActionType = 'Draft Decision'; - break; - case DECISION_TYPES.DISPATCH: - reviewActionType = 'to Dispatch'; - break; + case DECISION_TYPES.OMO_REQUEST: + reviewActionType = 'OMO'; + break; + case DECISION_TYPES.DRAFT_DECISION: + reviewActionType = 'Draft Decision'; + break; + case DECISION_TYPES.DISPATCH: + reviewActionType = 'to Dispatch'; + break; } return `Draft Decision | Submit ${reviewActionType}`; @@ -927,17 +927,20 @@ class QueueApp extends React.PureComponent { render={this.routedAssignToSingleTeam} /> @@ -1002,7 +1005,8 @@ class QueueApp extends React.PureComponent { render={this.routedReturnToCamo} /> @@ -1092,7 +1096,8 @@ class QueueApp extends React.PureComponent { render={this.routedCavcRemandReceived} /> @@ -1122,7 +1127,8 @@ class QueueApp extends React.PureComponent { /> Date: Fri, 4 Aug 2023 16:13:21 -0400 Subject: [PATCH 52/87] APPEALS-24997 Removed old useEffect from DateSelector --- client/app/components/DateSelector.jsx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/client/app/components/DateSelector.jsx b/client/app/components/DateSelector.jsx index aa39bcf46ae..f692a209cbf 100644 --- a/client/app/components/DateSelector.jsx +++ b/client/app/components/DateSelector.jsx @@ -53,14 +53,6 @@ export const DateSelector = (props) => { validateDate?.(value !== '' && errorMsg === null); }, [value]); - useEffect(() => { - if (validateDate) { - const dateIsValid = dateValidationError(value) === null && value !== ''; - - validateDate(dateIsValid); - } - }, [value]); - let max = '9999-12-31'; if (noFutureDates) { From 0b0ebed6fbc61ebcd2d1b51db358ad04fe5a5d7a Mon Sep 17 00:00:00 2001 From: Minhazur Rahaman Date: Mon, 7 Aug 2023 10:08:26 -0400 Subject: [PATCH 53/87] APPEALS-25000 buttons are now disabled when required information is not set --- client/app/queue/AssignToView.jsx | 2 +- client/app/queue/ChangeTaskTypeModal.jsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/client/app/queue/AssignToView.jsx b/client/app/queue/AssignToView.jsx index 56fdcb84a96..6c2351433ab 100644 --- a/client/app/queue/AssignToView.jsx +++ b/client/app/queue/AssignToView.jsx @@ -53,7 +53,7 @@ class AssignToView extends React.Component { this.state = { selectedValue: action ? action.value : null, assignToVHARegionalOfficeSelection: null, - instructions: existingInstructions + instructions: this?.props?.task?.type === 'HearingPostponementRequestMailTask' ? '' : existingInstructions }; } diff --git a/client/app/queue/ChangeTaskTypeModal.jsx b/client/app/queue/ChangeTaskTypeModal.jsx index 9711b0e443f..9ad9c90837d 100644 --- a/client/app/queue/ChangeTaskTypeModal.jsx +++ b/client/app/queue/ChangeTaskTypeModal.jsx @@ -104,6 +104,7 @@ class ChangeTaskTypeModal extends React.PureComponent { button={COPY.CHANGE_TASK_TYPE_SUBHEAD} pathAfterSubmit={`/queue/appeals/${this.props.appealId}`} submitButtonClassNames={['usa-button']} + submitDisabled={!this.validateForm()} > {error && {error.detail} From df08aec6375c9b1876ddf884f796f406d32ba293 Mon Sep 17 00:00:00 2001 From: Marc Steele <71673522+msteele96@users.noreply.github.com> Date: Mon, 7 Aug 2023 10:34:57 -0400 Subject: [PATCH 54/87] APPEALS-25001 Ignore CC issues Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> --- app/models/tasks/root_task.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/tasks/root_task.rb b/app/models/tasks/root_task.rb index 23dc40df819..5d46ed2e1d3 100644 --- a/app/models/tasks/root_task.rb +++ b/app/models/tasks/root_task.rb @@ -76,6 +76,7 @@ def hide_from_task_snapshot true end + # :reek:UtilityFunction def available_actions(user) return [Constants.TASK_ACTIONS.CREATE_MAIL_TASK.to_h] if RootTask.user_can_create_mail_task?(user) From d23f0829fbf439dc44efc6d101c2e55dc33fd0b4 Mon Sep 17 00:00:00 2001 From: Minhazur Rahaman Date: Mon, 7 Aug 2023 11:33:47 -0400 Subject: [PATCH 55/87] APPEALS 25000 added more feature tests --- spec/feature/queue/mail_task_spec.rb | 109 +++++++++++++++++---------- 1 file changed, 70 insertions(+), 39 deletions(-) diff --git a/spec/feature/queue/mail_task_spec.rb b/spec/feature/queue/mail_task_spec.rb index 908e520ba48..0c6b6e6a92e 100644 --- a/spec/feature/queue/mail_task_spec.rb +++ b/spec/feature/queue/mail_task_spec.rb @@ -117,14 +117,11 @@ # Attempt to change task type without including instuctions. find("div", class: "cf-select__option", text: new_task_type.label).click - find("button", text: COPY::CHANGE_TASK_TYPE_SUBHEAD).click - - # Instructions field is required - expect(page).to have_content(COPY::INSTRUCTIONS_ERROR_FIELD_REQUIRED) + find_button(text: COPY::CHANGE_TASK_TYPE_SUBHEAD, disabled: true) # Add instructions and try again new_instructions = generate_words(5) - fill_in("instructions", with: new_instructions) + fill_in("Provide instructions and context for this change:", with: new_instructions) find("button", text: COPY::CHANGE_TASK_TYPE_SUBHEAD).click # We should see a success message but remain on the case details page @@ -152,13 +149,20 @@ let(:hpr_task) { create(:hearing_postponement_request_mail_task, :with_unscheduled_hearing) } context "changing task type" do + it "submit button starts out disabled" do + visit("queue/appeals/#{hpr_task.appeal.uuid}") + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: COPY::CHANGE_TASK_TYPE_SUBHEAD) + modal = find(".cf-modal-body") + expect(modal).to have_button("Change task type", disabled: true) + end + it "current tasks should have new task" do appeal = hpr_task.appeal visit("queue/appeals/#{appeal.uuid}") click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: COPY::CHANGE_TASK_TYPE_SUBHEAD) find(".cf-select__control", text: "Select an action type").click find(".cf-select__option", text: "Change of address").click - fill_in(name: "Provide instructions and context for this change:", with: "instructions") + fill_in("Provide instructions and context for this change:", with: "instructions") click_button("Change task type") new_task = appeal.tasks.last most_recent_task = find("tr", text: "TASK", match: :first) @@ -171,7 +175,7 @@ click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: COPY::CHANGE_TASK_TYPE_SUBHEAD) find(".cf-select__control", text: "Select an action type").click find(".cf-select__option", text: "Change of address").click - fill_in(name: "Provide instructions and context for this change:", with: "instructions") + fill_in("Provide instructions and context for this change:", with: "instructions") click_button("Change task type") first_task_item = find("#case-timeline-table tr:nth-child(2)") expect(first_task_item).to have_content("CANCELLED ON\n#{hpr_task.updated_at.strftime('%m/%d/%Y')}") @@ -180,46 +184,73 @@ end end - it "assigning to new team" do - appeal = hpr_task.appeal - page = "queue/appeals/#{appeal.uuid}" - visit(page) - click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.ASSIGN_TO_TEAM.label) - find(".cf-select__control", text: "Select a team").click - find(".cf-select__option", text: "BVA Intake").click - fill_in(name: "Provide instructions and context for this action:", with: "instructions") - click_button("Submit") - new_task = appeal.tasks.last - visit(page) - most_recent_task = find("tr", text: "TASK", match: :first) - expect(most_recent_task).to have_content("ASSIGNED ON\n#{new_task.assigned_at.strftime('%m/%d/%Y')}") - expect(most_recent_task).to have_content("ASSIGNED TO\nBVA Intake") + context "assigning to new team" do + it "submit button starts out disabled" do + visit("queue/appeals/#{hpr_task.appeal.uuid}") + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.ASSIGN_TO_TEAM.label) + modal = find(".cf-modal-body") + expect(modal).to have_button("Submit", disabled: true) + end + + it "assigns to new team" do + appeal = hpr_task.appeal + page = "queue/appeals/#{appeal.uuid}" + visit(page) + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.ASSIGN_TO_TEAM.label) + find(".cf-select__control", text: "Select a team").click + find(".cf-select__option", text: "BVA Intake").click + fill_in("taskInstructions", with: "instructions") + click_button("Submit") + new_task = appeal.tasks.last + visit(page) + most_recent_task = find("tr", text: "TASK", match: :first) + expect(most_recent_task).to have_content("ASSIGNED ON\n#{new_task.assigned_at.strftime('%m/%d/%Y')}") + expect(most_recent_task).to have_content("ASSIGNED TO\nBVA Intake") + end end - it "assign to person" do - new_user = User.create!(css_id: "NEW_USER", full_name: "John Smith", station_id: "101") - HearingAdmin.singleton.add_user(new_user) - appeal = hpr_task.appeal - page = "queue/appeals/#{appeal.uuid}" - visit(page) - click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.ASSIGN_TO_PERSON.label) - find(".cf-select__control", text: User.current_user.full_name).click - find(".cf-select__option", text: new_user.full_name).click - fill_in(name: "Provide instructions and context for this action:", with: "instructions") - click_button("Submit") - new_task = appeal.tasks.last - visit(page) - most_recent_task = find("tr", text: "TASK", match: :first) - expect(most_recent_task).to have_content("ASSIGNED ON\n#{new_task.assigned_at.strftime('%m/%d/%Y')}") - expect(most_recent_task).to have_content("ASSIGNED TO\n#{new_user.css_id}") + context "assigning to person" do + it "submit button starts out disabled" do + visit("queue/appeals/#{hpr_task.appeal.uuid}") + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, + text: Constants.TASK_ACTIONS.ASSIGN_TO_PERSON.label) + modal = find(".cf-modal-body") + expect(modal).to have_button("Submit", disabled: true) + end + + it "assigns to person" do + new_user = User.create!(css_id: "NEW_USER", full_name: "John Smith", station_id: "101") + HearingAdmin.singleton.add_user(new_user) + appeal = hpr_task.appeal + page = "queue/appeals/#{appeal.uuid}" + visit(page) + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, + text: Constants.TASK_ACTIONS.ASSIGN_TO_PERSON.label) + find(".cf-select__control", text: User.current_user.full_name).click + find(".cf-select__option", text: new_user.full_name).click + fill_in("taskInstructions", with: "instructions") + click_button("Submit") + new_task = appeal.tasks.last + visit(page) + most_recent_task = find("tr", text: "TASK", match: :first) + expect(most_recent_task).to have_content("ASSIGNED ON\n#{new_task.assigned_at.strftime('%m/%d/%Y')}") + expect(most_recent_task).to have_content("ASSIGNED TO\n#{new_user.css_id}") + end end context "cancelling task" do + it "submit button starts out disabled" do + visit("queue/appeals/#{hpr_task.appeal.uuid}") + click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.CANCEL_TASK.label) + modal = find(".cf-modal-body") + expect(modal).to have_button("Submit", disabled: true) + end + it "should remove HearingPostponementRequestTask from current tasks" do page = "queue/appeals/#{hpr_task.appeal.uuid}" visit(page) click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.CANCEL_TASK.label) - fill_in(name: "Provide instructions and context for this action:", with: "instructions") + fill_in("taskInstructions", with: "instructions") click_button("Submit") visit(page) most_recent_task = find("tr", text: "TASK", match: :first) @@ -230,7 +261,7 @@ page = "queue/appeals/#{hpr_task.appeal.uuid}" visit(page) click_dropdown(prompt: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL, text: Constants.TASK_ACTIONS.CANCEL_TASK.label) - fill_in(name: "Provide instructions and context for this action:", with: "instructions") + fill_in("taskInstructions", with: "instructions") click_button("Submit") visit(page) first_task_item = find("#case-timeline-table tr:nth-child(2)") From 9e2421add674823fb2645b59e6d4c4742e3865c7 Mon Sep 17 00:00:00 2001 From: Matthew Thornton Date: Mon, 7 Aug 2023 13:13:29 -0400 Subject: [PATCH 56/87] APPEALS-24997: Fix typo in unrelated portion of modal --- client/app/queue/components/CancelTaskModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/app/queue/components/CancelTaskModal.jsx b/client/app/queue/components/CancelTaskModal.jsx index 9db54ac73de..28506bafac0 100644 --- a/client/app/queue/components/CancelTaskModal.jsx +++ b/client/app/queue/components/CancelTaskModal.jsx @@ -116,7 +116,7 @@ const CancelTaskModal = (props) => { // COPY.INSTRUCTIONS_ERROR_FIELD_REQUIRED : null} id="taskInstructions" onChange={setInstructions} - placeholder="This is a description of instuctions and context for this action." + placeholder="This is a description of instructions and context for this action." value={instructions} /> } From 33254e32b7ffd1f50b2caf32305d6eebaed7569a Mon Sep 17 00:00:00 2001 From: Minhazur Rahaman Date: Mon, 7 Aug 2023 13:24:01 -0400 Subject: [PATCH 57/87] APPEALS-25000 removed highlighting error messages --- client/app/queue/AssignToView.jsx | 9 +------- client/app/queue/ChangeTaskTypeModal.jsx | 5 ----- client/app/queue/CreateMailTaskDialog.jsx | 22 +------------------ .../app/queue/components/CancelTaskModal.jsx | 7 +----- 4 files changed, 3 insertions(+), 40 deletions(-) diff --git a/client/app/queue/AssignToView.jsx b/client/app/queue/AssignToView.jsx index 6c2351433ab..74c385ad2c8 100644 --- a/client/app/queue/AssignToView.jsx +++ b/client/app/queue/AssignToView.jsx @@ -267,7 +267,7 @@ class AssignToView extends React.Component { } render = () => { - const { assigneeAlreadySelected, highlightFormItems, task } = this.props; + const { assigneeAlreadySelected, task } = this.props; const action = getAction(this.props); const actionData = taskActionData(this.props); @@ -324,7 +324,6 @@ class AssignToView extends React.Component { searchable hideLabel={actionData.drop_down_label ? null : true} label={this.determineDropDownLabel(actionData)} - errorMessage={highlightFormItems && !this.state.selectedValue ? 'Choose one' : null} placeholder={this.determinePlaceholder(this.props, actionData)} value={this.state.selectedValue} onChange={(option) => this.setState({ selectedValue: option ? option.value : null })} @@ -346,8 +345,6 @@ class AssignToView extends React.Component { this.setState({ instructions: value })} value={this.state.instructions} @@ -372,7 +369,6 @@ AssignToView.propTypes = { veteranFullName: PropTypes.string }), assigneeAlreadySelected: PropTypes.bool, - highlightFormItems: PropTypes.bool, isReassignAction: PropTypes.bool, isTeamAssign: PropTypes.bool, onReceiveAmaTasks: PropTypes.func, @@ -391,10 +387,7 @@ AssignToView.propTypes = { }; const mapStateToProps = (state, ownProps) => { - const { highlightFormItems } = state.ui; - return { - highlightFormItems, task: taskById(state, { taskId: ownProps.taskId }), appeal: appealWithDetailSelector(state, ownProps) }; diff --git a/client/app/queue/ChangeTaskTypeModal.jsx b/client/app/queue/ChangeTaskTypeModal.jsx index 9ad9c90837d..9f8e9180d59 100644 --- a/client/app/queue/ChangeTaskTypeModal.jsx +++ b/client/app/queue/ChangeTaskTypeModal.jsx @@ -69,14 +69,12 @@ class ChangeTaskTypeModal extends React.PureComponent { } actionForm = () => { - const { highlightFormItems } = this.props; const { instructions, typeOption } = this.state; return
this.setState({ instructions: value })} value={instructions} /> @@ -120,7 +117,6 @@ ChangeTaskTypeModal.propTypes = { title: PropTypes.string, detail: PropTypes.string }), - highlightFormItems: PropTypes.bool, highlightInvalidFormItems: PropTypes.func, onReceiveAmaTasks: PropTypes.func, requestPatch: PropTypes.func, @@ -132,7 +128,6 @@ ChangeTaskTypeModal.propTypes = { }; const mapStateToProps = (state, ownProps) => ({ - highlightFormItems: state.ui.highlightFormItems, error: state.ui.messages.error, appeal: appealWithDetailSelector(state, ownProps), task: taskById(state, { taskId: ownProps.taskId }) diff --git a/client/app/queue/CreateMailTaskDialog.jsx b/client/app/queue/CreateMailTaskDialog.jsx index 5260cfce5b9..bc95efd6ac9 100644 --- a/client/app/queue/CreateMailTaskDialog.jsx +++ b/client/app/queue/CreateMailTaskDialog.jsx @@ -102,7 +102,7 @@ export class CreateMailTaskDialog extends React.Component { isHearingRequestMailTask = () => (this.state.selectedValue || '').match(/Hearing.*RequestMailTask/); render = () => { - const { highlightFormItems, task } = this.props; + const { task } = this.props; if (!task || task.availableActions.length === 0) { return null; @@ -121,11 +121,6 @@ export class CreateMailTaskDialog extends React.Component { name="Correspondence type selector" searchable hideLabel - errorMessage={ - highlightFormItems && !this.state.selectedValue ? - 'Choose one' : - null - } placeholder={COPY.MAIL_TASK_DROPDOWN_TYPE_SELECTOR_LABEL} value={this.state.selectedValue} onChange={(option) => @@ -138,23 +133,12 @@ export class CreateMailTaskDialog extends React.Component { this.isHearingRequestMailTask() && this.setState({ eFolderUrl: value })} value={this.state.eFolderUrl} /> } this.setState({ instructions: value })} value={this.state.instructions} @@ -169,7 +153,6 @@ CreateMailTaskDialog.propTypes = { externalId: PropTypes.string, }), appealId: PropTypes.string, - highlightFormItems: PropTypes.bool, history: PropTypes.shape({ location: PropTypes.shape({ pathname: PropTypes.string, @@ -184,10 +167,7 @@ CreateMailTaskDialog.propTypes = { }; const mapStateToProps = (state, ownProps) => { - const { highlightFormItems } = state.ui; - return { - highlightFormItems, task: taskById(state, { taskId: ownProps.taskId }), appeal: appealWithDetailSelector(state, ownProps), }; diff --git a/client/app/queue/components/CancelTaskModal.jsx b/client/app/queue/components/CancelTaskModal.jsx index 09d9bc97178..68e103e6aa8 100644 --- a/client/app/queue/components/CancelTaskModal.jsx +++ b/client/app/queue/components/CancelTaskModal.jsx @@ -16,7 +16,7 @@ import QueueFlowModal from './QueueFlowModal'; /* eslint-disable camelcase */ const CancelTaskModal = (props) => { - const { task, hearingDay, highlightFormItems } = props; + const { task, hearingDay } = props; const taskData = taskActionData(props); // Show task instructions by default @@ -113,8 +113,6 @@ const CancelTaskModal = (props) => { {get(taskData, 'show_instructions', true) && { {shouldShowTaskInstructions && ({ task: taskById(state, { taskId: ownProps.taskId }), hearingDay: state.ui.hearingDay, - highlightFormItems: state.ui.highlightFormItems }); const mapDispatchToProps = (dispatch) => bindActionCreators({ From 1e89934e7d715812a322c278ec2989395f7c51d8 Mon Sep 17 00:00:00 2001 From: Minhazur Rahaman Date: Mon, 7 Aug 2023 14:14:55 -0400 Subject: [PATCH 58/87] APPEALS-25000 fixed colocated task feature test --- spec/feature/queue/colocated_task_queue_spec.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/spec/feature/queue/colocated_task_queue_spec.rb b/spec/feature/queue/colocated_task_queue_spec.rb index 88a5af39375..081267de37c 100644 --- a/spec/feature/queue/colocated_task_queue_spec.rb +++ b/spec/feature/queue/colocated_task_queue_spec.rb @@ -185,10 +185,7 @@ # Attempt to change task type without including instuctions. find("div", class: "cf-select__option", text: new_task_type.label).click - find("button", text: COPY::CHANGE_TASK_TYPE_SUBHEAD).click - - # Instructions field is required - expect(page).to have_content(COPY::INSTRUCTIONS_ERROR_FIELD_REQUIRED) + find_button(text: COPY::CHANGE_TASK_TYPE_SUBHEAD, disabled: true) # Add instructions and try again instructions = generate_words(5) From 7d3fe81831f2e5d19df2f0c93fb4fe175c524620 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Tue, 8 Aug 2023 09:59:53 -0400 Subject: [PATCH 59/87] APPEALS-24997 Updated CAVC modal snapshots after COPY standardization --- .../__snapshots__/AddCavcDatesModal.test.js.snap | 12 ++++++------ .../__snapshots__/AddCavcRemandView.test.js.snap | 6 +++--- .../__snapshots__/EditCavcRemandForm.test.js.snap | 14 +++++++------- .../CavcReviewExtensionRequestModal.test.js.snap | 6 +++--- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/client/test/app/queue/cavc/__snapshots__/AddCavcDatesModal.test.js.snap b/client/test/app/queue/cavc/__snapshots__/AddCavcDatesModal.test.js.snap index 598ac800ead..8e4e40ffde8 100644 --- a/client/test/app/queue/cavc/__snapshots__/AddCavcDatesModal.test.js.snap +++ b/client/test/app/queue/cavc/__snapshots__/AddCavcDatesModal.test.js.snap @@ -525,7 +525,7 @@ exports[`AddCavcDatesModal renders correctly 1`] = ` characterLimitTopRight={false} disabled={false} errorMessage={null} - label="Provide context and instructions for this action" + label="Provide instructions and context for this action" name="context-and-instructions-textBox" onChange={[Function]} optional={false} @@ -541,13 +541,13 @@ exports[`AddCavcDatesModal renders correctly 1`] = ` > - Provide context and instructions for this action + Provide instructions and context for this action @@ -1180,7 +1180,7 @@ exports[`AddCavcDatesModal submits succesfully 1`] = ` characterLimitTopRight={false} disabled={false} errorMessage={null} - label="Provide context and instructions for this action" + label="Provide instructions and context for this action" name="context-and-instructions-textBox" onChange={[Function]} optional={false} @@ -1197,13 +1197,13 @@ exports[`AddCavcDatesModal submits succesfully 1`] = ` > - Provide context and instructions for this action + Provide instructions and context for this action diff --git a/client/test/app/queue/cavc/__snapshots__/AddCavcRemandView.test.js.snap b/client/test/app/queue/cavc/__snapshots__/AddCavcRemandView.test.js.snap index f56b0f7b28e..701cb6b613d 100644 --- a/client/test/app/queue/cavc/__snapshots__/AddCavcRemandView.test.js.snap +++ b/client/test/app/queue/cavc/__snapshots__/AddCavcRemandView.test.js.snap @@ -4004,7 +4004,7 @@ exports[`AddCavcRemandView renders correctly 1`] = ` characterLimitTopRight={false} disabled={false} errorMessage={null} - label="Provide context and instructions for this action" + label="Provide instructions and context for this action" name="context-and-instructions-textBox" onChange={[Function]} optional={false} @@ -4021,13 +4021,13 @@ exports[`AddCavcRemandView renders correctly 1`] = ` > - Provide context and instructions for this action + Provide instructions and context for this action diff --git a/client/test/app/queue/cavc/__snapshots__/EditCavcRemandForm.test.js.snap b/client/test/app/queue/cavc/__snapshots__/EditCavcRemandForm.test.js.snap index 0e5c9e100b8..bb357427e6c 100644 --- a/client/test/app/queue/cavc/__snapshots__/EditCavcRemandForm.test.js.snap +++ b/client/test/app/queue/cavc/__snapshots__/EditCavcRemandForm.test.js.snap @@ -362,7 +362,7 @@ exports[`EditCavcRemandForm adding new all feature toggles enabled renders corre > - Provide context and instructions for this action + Provide instructions and context for this action @@ -841,7 +841,7 @@ exports[`EditCavcRemandForm adding new with Remand decision renders correctly wi > - Provide context and instructions for this action + Provide instructions and context for this action @@ -1320,7 +1320,7 @@ exports[`EditCavcRemandForm adding new with Remand decision renders correctly wi > - Provide context and instructions for this action + Provide instructions and context for this action @@ -1814,7 +1814,7 @@ exports[`EditCavcRemandForm adding new with Remand decision renders correctly wi > - Provide context and instructions for this action + Provide instructions and context for this action @@ -2263,7 +2263,7 @@ exports[`EditCavcRemandForm adding new with Reversal decision renders correctly > - Provide context and instructions for this action + Provide instructions and context for this action @@ -2726,7 +2726,7 @@ exports[`EditCavcRemandForm adding new with Reversal decision renders correctly > - Provide context and instructions for this action + Provide instructions and context for this action @@ -3094,7 +3094,7 @@ exports[`EditCavcRemandForm editing existing all feature toggles enabled renders > - Provide context and instructions for this action + Provide instructions and context for this action diff --git a/client/test/app/queue/components/__snapshots__/CavcReviewExtensionRequestModal.test.js.snap b/client/test/app/queue/components/__snapshots__/CavcReviewExtensionRequestModal.test.js.snap index 8191032a790..599042c4ebe 100644 --- a/client/test/app/queue/components/__snapshots__/CavcReviewExtensionRequestModal.test.js.snap +++ b/client/test/app/queue/components/__snapshots__/CavcReviewExtensionRequestModal.test.js.snap @@ -217,7 +217,7 @@ exports[`CavcReviewExtensionRequestModal renders correctly 1`] = ` characterLimitTopRight={false} disabled={false} errorMessage={null} - label="Provide context and instructions for this action" + label="Provide instructions and context for this action" name="instructions" onChange={[Function]} optional={false} @@ -231,13 +231,13 @@ exports[`CavcReviewExtensionRequestModal renders correctly 1`] = ` htmlFor="instructions" > - Provide context and instructions for this action + Provide instructions and context for this action From af1ebc5c8965fe43705b3fd539706b157060327d Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Tue, 8 Aug 2023 10:29:45 -0400 Subject: [PATCH 60/87] APPEALS-24997 changed flow modal default classname from usa-button-secondary to usa-button: --- client/app/components/FlowModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/app/components/FlowModal.jsx b/client/app/components/FlowModal.jsx index 5c518d46db7..99ce9a2ddb0 100644 --- a/client/app/components/FlowModal.jsx +++ b/client/app/components/FlowModal.jsx @@ -84,7 +84,7 @@ export default class FlowModal extends React.PureComponent { FlowModal.defaultProps = { button: COPY.MODAL_SUBMIT_BUTTON, - submitButtonClassNames: ['usa-button-secondary', 'usa-button-hover', 'usa-button-warning'], + submitButtonClassNames: ['usa-button', 'usa-button-hover', 'usa-button-warning'], pathAfterSubmit: '/queue', submitDisabled: false, title: '', From 8bfbe0766bd717a93a1252ab958c96b1ae035995 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Tue, 8 Aug 2023 10:46:29 -0400 Subject: [PATCH 61/87] APPEALS-24997 fixed typo in queue/constants and removed comment --- client/app/queue/constants.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/app/queue/constants.js b/client/app/queue/constants.js index e139e897cfa..f7cdf5b2157 100644 --- a/client/app/queue/constants.js +++ b/client/app/queue/constants.js @@ -211,8 +211,7 @@ export const PAGE_TITLES = { CONVERT_HEARING_TO_VIRTUAL: 'Change Hearing Request Type to Virtual', CONVERT_HEARING_TO_VIDEO: 'Change Hearing Request Type to Video', CONVERT_HEARING_TO_CENTRAL: 'Change Hearing Request Type to Central', - // Confirm with UX title for HPR - COMPLETE_HEARING_POSTPONEMENT_REQUEST: 'Complete Heaering Postponement Request' + COMPLETE_HEARING_POSTPONEMENT_REQUEST: 'Complete Hearing Postponement Request' }; export const CUSTOM_HOLD_DURATION_TEXT = 'Custom'; From b83e11dc075e45c603e2881994e475caf80e2802 Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Tue, 8 Aug 2023 11:06:03 -0400 Subject: [PATCH 62/87] APPEALS-24997 Added period to end of alert in modal --- .../CompleteHearingPostponementRequestModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index bc6e6c71c54..a6f1136135f 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -103,7 +103,7 @@ const CompleteHearingPostponementRequestModal = (props) => { /> {state.granted && Date: Tue, 8 Aug 2023 11:06:42 -0400 Subject: [PATCH 63/87] APPEALS-249979 fixed typo --- .../CompleteHearingPostponementRequestModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx index a6f1136135f..d741e2d4b45 100644 --- a/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx +++ b/client/app/queue/components/hearingMailRequestModals/CompleteHearingPostponementRequestModal.jsx @@ -122,7 +122,7 @@ const CompleteHearingPostponementRequestModal = (props) => { {state.granted && dispatch({ type: 'scheduledOption', payload: value })} From a68ab05f03fc4cbfdcd325d7755fd891f966224d Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Tue, 8 Aug 2023 11:07:49 -0400 Subject: [PATCH 64/87] APPEALS-24997 Removed unnecessary prop types declaration --- client/app/components/Alert.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/app/components/Alert.jsx b/client/app/components/Alert.jsx index af38296d9ad..2d851edb3a8 100644 --- a/client/app/components/Alert.jsx +++ b/client/app/components/Alert.jsx @@ -55,7 +55,6 @@ Alert.propTypes = { * Sets `.cf-margin-bottom-2rem` class */ lowerMargin: PropTypes.bool, - lowerMarginTop: PropTypes.bool, message: PropTypes.node, /** From 1fb433dfd6c2c84b722d8b705630bd64877dcade Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Tue, 8 Aug 2023 11:16:40 -0400 Subject: [PATCH 65/87] APPEALS-24997 manually update schema to remove MST/PACT tables --- db/schema.rb | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index 5c15532cc78..0fa2ef9ac77 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -597,8 +597,6 @@ t.string "diagnostic_code", comment: "If a decision resulted in a rating, this is the rating issue's diagnostic code." t.string "disposition", comment: "The disposition for a decision issue. Dispositions made in Caseflow and dispositions made in VBMS can have different values." t.date "end_product_last_action_date", comment: "After an end product gets synced with a status of CLR (cleared), the end product's last_action_date is saved on any decision issues that are created as a result. This is used as a proxy for decision date for non-rating issues that are processed in VBMS because they don't have a rating profile date, and the exact decision date is not available." - t.boolean "mst_status", default: false, comment: "Indicates if decision issue is related to Military Sexual Trauma (MST)" - t.boolean "pact_status", default: false, comment: "Indicates if decision issue is related to Promise to Address Comprehensive Toxics (PACT) Act" t.string "participant_id", null: false, comment: "The Veteran's participant id." t.string "percent_number", comment: "percent_number from RatingIssue (prcntNo from Rating Profile)" t.string "rating_issue_reference_id", comment: "Identifies the specific issue on the rating that resulted from the decision issue (a rating issue can be connected to multiple contentions)." @@ -1474,13 +1472,9 @@ t.string "ineligible_reason", comment: "The reason for a Request Issue being ineligible. If a Request Issue has an ineligible_reason, it is still captured, but it will not get a contention in VBMS or a decision." t.boolean "is_predocket_needed", comment: "Indicates whether or not an issue has been selected to go to the pre-docket queue opposed to normal docketing." t.boolean "is_unidentified", comment: "Indicates whether a Request Issue is unidentified, meaning it wasn't found in the list of contestable issues, and is not a new nonrating issue. Contentions for unidentified issues are created on a rating End Product if processed in VBMS but without the issue description, and someone is required to edit it in Caseflow before proceeding with the decision." - t.boolean "mst_status", default: false, comment: "Indicates if issue is related to Military Sexual Trauma (MST)" - t.text "mst_status_update_reason_notes", comment: "The reason for why Request Issue is Military Sexual Trauma (MST)" t.string "nonrating_issue_category", comment: "The category selected for nonrating request issues. These vary by business line." t.string "nonrating_issue_description", comment: "The user entered description if the issue is a nonrating issue" t.text "notes", comment: "Notes added by the Claims Assistant when adding request issues. This may be used to capture handwritten notes on the form, or other comments the CA wants to capture." - t.boolean "pact_status", default: false, comment: "Indicates if issue is related to Promise to Address Comprehensive Toxics (PACT) Act" - t.text "pact_status_update_reason_notes", comment: "The reason for why Request Issue is Promise to Address Comprehensive Toxics (PACT) Act" t.string "ramp_claim_id", comment: "If a rating issue was created as a result of an issue intaken for a RAMP Review, it will be connected to the former RAMP issue by its End Product's claim ID." t.datetime "rating_issue_associated_at", comment: "Timestamp when a contention and its contested rating issue are associated in VBMS." t.string "split_issue_status", comment: "If a request issue is part of a split, on_hold status applies to the original request issues while active are request issues on splitted appeals" @@ -1491,8 +1485,6 @@ t.datetime "updated_at", comment: "Automatic timestamp whenever the record changes." t.string "vacols_id", comment: "The vacols_id of the legacy appeal that had an issue found to match the request issue." t.integer "vacols_sequence_id", comment: "The vacols_sequence_id, for the specific issue on the legacy appeal which the Claims Assistant determined to match the request issue on the Decision Review. A combination of the vacols_id (for the legacy appeal), and vacols_sequence_id (for which issue on the legacy appeal), is required to identify the issue being opted-in." - t.boolean "vbms_mst_status", default: false, comment: "Indicates if issue is related to Military Sexual Trauma (MST) and was imported from VBMS" - t.boolean "vbms_pact_status", default: false, comment: "Indicates if issue is related to Promise to Address Comprehensive Toxics (PACT) Act and was imported from VBMS" t.boolean "verified_unidentified_issue", comment: "A verified unidentified issue allows an issue whose rating data is missing to be intaken as a regular rating issue. In order to be marked as verified, a VSR needs to confirm that they were able to find the record of the decision for the issue." t.string "veteran_participant_id", comment: "The veteran participant ID. This should be unique in upstream systems and used in the future to reconcile duplicates." t.index ["closed_at"], name: "index_request_issues_on_closed_at" @@ -1518,8 +1510,6 @@ t.integer "edited_request_issue_ids", comment: "An array of the request issue IDs that were edited during this request issues update", array: true t.string "error", comment: "The error message if the last attempt at processing the request issues update was not successful." t.datetime "last_submitted_at", comment: "Timestamp for when the processing for the request issues update was last submitted. Used to determine how long to continue retrying the processing job. Can be reset to allow for additional retries." - t.integer "mst_edited_request_issue_ids", comment: "An array of the request issue IDs that were updated to be associated with MST in request issues update", array: true - t.integer "pact_edited_request_issue_ids", comment: "An array of the request issue IDs that were updated to be associated with PACT in request issues update", array: true t.datetime "processed_at", comment: "Timestamp for when the request issue update successfully completed processing." t.bigint "review_id", null: false, comment: "The ID of the decision review edited." t.string "review_type", null: false, comment: "The type of the decision review edited." @@ -1568,26 +1558,6 @@ t.index ["sent_by_id"], name: "index_sent_hearing_email_events_on_sent_by_id" end - create_table "special_issue_changes", force: :cascade do |t| - t.bigint "appeal_id", null: false, comment: "AMA or Legacy Appeal ID that the issue is tied to" - t.string "appeal_type", null: false, comment: "Appeal Type (Appeal or LegacyAppeal)" - t.string "change_category", null: false, comment: "Type of change that occured to the issue (Established Issue, Added Issue, Edited Issue, Removed Issue)" - t.datetime "created_at", null: false, comment: "Date the special issue change was made" - t.string "created_by_css_id", null: false, comment: "CSS ID of the user that made the special issue change" - t.bigint "created_by_id", null: false, comment: "User ID of the user that made the special issue change" - t.bigint "decision_issue_id", comment: "ID of the decision issue that had a special issue change from its corresponding request issue" - t.bigint "issue_id", null: false, comment: "ID of the issue that was changed" - t.boolean "mst_from_vbms", comment: "Indication that the MST status originally came from VBMS on intake" - t.string "mst_reason_for_change", comment: "Reason for changing the MST status on an issue" - t.boolean "original_mst_status", null: false, comment: "Original MST special issue status of the issue" - t.boolean "original_pact_status", null: false, comment: "Original PACT special issue status of the issue" - t.boolean "pact_from_vbms" - t.string "pact_reason_for_change", comment: "Reason for changing the PACT status on an issue" - t.bigint "task_id", null: false, comment: "Task ID of the IssueUpdateTask or EstablishmentTask used to log this issue in the case timeline" - t.boolean "updated_mst_status", comment: "Updated MST special issue status of the issue" - t.boolean "updated_pact_status", comment: "Updated PACT special issue status of the issue" - end - create_table "special_issue_lists", comment: "Associates special issues to an AMA or legacy appeal for Caseflow Queue. Caseflow Dispatch uses special issues stored in legacy_appeals. They are intentionally disconnected.", force: :cascade do |t| t.bigint "appeal_id", comment: "The ID of the appeal associated with this record" t.string "appeal_type", comment: "The type of appeal associated with this record" From 6cb359625b08cc16692bc0271710a51840beb82f Mon Sep 17 00:00:00 2001 From: Jeff Marks Date: Tue, 8 Aug 2023 15:47:09 -0400 Subject: [PATCH 66/87] APPEALS-24997 update snapshots for AddCavcDatesModal jest test --- .../__snapshots__/AddCavcDatesModal.test.js.snap | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/test/app/queue/cavc/__snapshots__/AddCavcDatesModal.test.js.snap b/client/test/app/queue/cavc/__snapshots__/AddCavcDatesModal.test.js.snap index 8e4e40ffde8..e3b65e62a60 100644 --- a/client/test/app/queue/cavc/__snapshots__/AddCavcDatesModal.test.js.snap +++ b/client/test/app/queue/cavc/__snapshots__/AddCavcDatesModal.test.js.snap @@ -268,7 +268,7 @@ exports[`AddCavcDatesModal renders correctly 1`] = ` submit={[Function]} submitButtonClassNames={ Array [ - "usa-button-secondary", + "usa-button", "usa-button-hover", "usa-button-warning", ] @@ -290,7 +290,7 @@ exports[`AddCavcDatesModal renders correctly 1`] = ` }, Object { "classNames": Array [ - "usa-button-secondary", + "usa-button", "usa-button-hover", "usa-button-warning", ], @@ -600,7 +600,7 @@ exports[`AddCavcDatesModal renders correctly 1`] = `