diff --git a/client/app/hearings/components/HearingTypeConversionForm.jsx b/client/app/hearings/components/HearingTypeConversionForm.jsx
new file mode 100644
index 00000000000..9d2684b7208
--- /dev/null
+++ b/client/app/hearings/components/HearingTypeConversionForm.jsx
@@ -0,0 +1,100 @@
+import React, { useState } from 'react';
+import AppSegment from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/AppSegment';
+import PropTypes from 'prop-types';
+import { sprintf } from 'sprintf-js';
+
+import { marginTop, saveButton, cancelButton } from './details/style';
+import { HelperText } from './VirtualHearings/HelperText';
+import COPY from '../../../COPY';
+import { getAppellantTitle } from '../utils';
+import { RepresentativeSection } from './VirtualHearings/RepresentativeSection';
+import { AppellantSection } from './VirtualHearings/AppellantSection';
+import Button from '../../components/Button';
+
+export const HearingTypeConversionForm = ({
+ type,
+ appeal
+}) => {
+ // Create and manage the loading state
+ const [loading, setLoading] = useState(false);
+
+ // reset any states
+ const reset = () => setLoading(false);
+
+ // 'Appellant' or 'Veteran'
+ const appellantTitle = getAppellantTitle(appeal?.appellantIsNotVeteran);
+
+ /* eslint-disable camelcase */
+ // powerOfAttorney gets loaded into redux store when case details page loads
+ const hearing = {
+ representative: appeal?.powerOfAttorney?.representative_name,
+ representativeType: appeal?.powerOfAttorney?.representative_type,
+ appellantFullName: appeal?.appellantFullName
+ };
+
+ // veteranInfo gets loaded into redux store when case details page loads
+ const virtualHearing = {
+ appellantEmail: appeal?.veteranInfo?.veteran?.email_address,
+ representativeEmail: appeal?.powerOfAttorney?.representative_email_address,
+ };
+ /* eslint-enable camelcase */
+
+ // Set the section props
+ const sectionProps = {
+ appellantTitle,
+ hearing,
+ readOnly: true,
+ showDivider: false,
+ showOnlyAppellantName: true,
+ type,
+ virtualHearing,
+ };
+
+ const convertTitle = sprintf(COPY.CONVERT_HEARING_TYPE_TITLE, type);
+
+ return (
+
+
+ {convertTitle}
+
+
+
+
+
+
+ {
+ reset();
+ history.goBack();
+ }
+ }
+ styling={cancelButton}
+ >
+ Cancel
+
+
+
+ {convertTitle}
+
+
+
+
+ );
+};
+
+HearingTypeConversionForm.propTypes = {
+ appeal: PropTypes.object,
+ // Router inherited props
+ history: PropTypes.object,
+ type: PropTypes.string
+};
diff --git a/client/app/hearings/components/HearingTypeConversionForm.stories.js b/client/app/hearings/components/HearingTypeConversionForm.stories.js
new file mode 100644
index 00000000000..76a02fdde2a
--- /dev/null
+++ b/client/app/hearings/components/HearingTypeConversionForm.stories.js
@@ -0,0 +1,46 @@
+import React from 'react';
+
+import { HearingTypeConversionForm } from './HearingTypeConversionForm';
+
+import { amaAppealForTravelBoard } from '../../../test/data/appeals';
+
+export default {
+ title: 'Hearings/Components/HearingTypeConversionForm',
+ component: HearingTypeConversionForm,
+ parameters: {
+ docs: {
+ inlineStories: false,
+ iframeHeight: 760,
+ },
+ }
+};
+
+const Template = (args) => (
+
+);
+
+export const Basic = Template.bind({});
+Basic.args = {
+ appeal: {
+ ...amaAppealForTravelBoard
+ },
+ type: "Virtual"
+}
+
+export const Appellant = Template.bind({});
+Appellant.args = {
+ ...Basic.args,
+ appeal: {
+ ...Basic.args.appeal,
+ appellantIsNotVeteran: true
+ }
+}
+
+export const CentralOffice = Template.bind({});
+CentralOffice.args = {
+ ...Basic.args,
+ appeal: {
+ ...Basic.args.appeal,
+ closestRegionalOfficeLabel: "Central Office"
+ }
+}
diff --git a/client/app/hearings/components/HearingTypeConversionForm.test.js b/client/app/hearings/components/HearingTypeConversionForm.test.js
new file mode 100644
index 00000000000..94f41435121
--- /dev/null
+++ b/client/app/hearings/components/HearingTypeConversionForm.test.js
@@ -0,0 +1,47 @@
+import React from 'react';
+
+import { HearingTypeConversionForm } from 'app/hearings/components/HearingTypeConversionForm';
+
+import { mount } from 'enzyme';
+import { amaAppealForTravelBoard } from 'test/data';
+import { VirtualHearingSection } from 'app/hearings/components/VirtualHearings/Section';
+import { AddressLine } from 'app/hearings/components/details/Address';
+import { VirtualHearingEmail } from 'app/hearings/components/VirtualHearings/Emails';
+import { getAppellantTitle } from 'app/hearings/utils';
+
+describe('HearingTypeConversionForm', () => {
+ test('Matches snapshot with default props', () => {
+ const hearingTypeConversionForm = mount(
+
+ );
+
+ // Assertions
+ expect(hearingTypeConversionForm.find(VirtualHearingSection)).toHaveLength(2);
+ expect(hearingTypeConversionForm.find(AddressLine)).toHaveLength(1);
+ expect(hearingTypeConversionForm.find(VirtualHearingEmail)).toHaveLength(2);
+ expect(hearingTypeConversionForm).toMatchSnapshot();
+ });
+
+ test('Does not show a divider on top of Appellant Section', () => {
+ const hearingTypeConversionForm = mount(
+
+ )
+
+ expect(
+ hearingTypeConversionForm.
+ findWhere(
+ (node) => node.prop('label') === `${getAppellantTitle(amaAppealForTravelBoard.appellantIsNotVeteran)}`
+ ).
+ prop('showDivider')
+ ).toEqual(false);
+ expect(hearingTypeConversionForm.find('.cf-help-divider')).toHaveLength(1);
+ expect(hearingTypeConversionForm).toMatchSnapshot();
+ });
+});
+
diff --git a/client/app/hearings/components/ScheduleVeteran.jsx b/client/app/hearings/components/ScheduleVeteran.jsx
index 932bb1d1441..d41cec13dba 100644
--- a/client/app/hearings/components/ScheduleVeteran.jsx
+++ b/client/app/hearings/components/ScheduleVeteran.jsx
@@ -15,7 +15,7 @@ import { formatDateStr } from '../../util/DateUtil';
import Alert from '../../components/Alert';
import { marginTop, regionalOfficeSection, saveButton, cancelButton } from './details/style';
import { find } from 'lodash';
-import { getAppellantTitleForHearing } from '../utils';
+import { getAppellantTitle } from '../utils';
import { onChangeFormData } from '../../components/common/actions';
import { ScheduleVeteranForm } from './ScheduleVeteranForm';
import { HEARING_REQUEST_TYPES } from '../constants';
@@ -37,7 +37,7 @@ export const ScheduleVeteran = ({
const [errors, setErrors] = useState({});
// Get the appellant title ('Veteran' or 'Appellant')
- const appellantTitle = getAppellantTitleForHearing(appeal);
+ const appellantTitle = getAppellantTitle(appeal?.apppellantIsNotVeteran);
// Get the selected hearing day
const selectedHearingDay = assignHearingForm?.hearingDay || hearingDay;
diff --git a/client/app/hearings/components/VirtualHearingModal.jsx b/client/app/hearings/components/VirtualHearingModal.jsx
index a97ea8e00e1..ab270b1f468 100644
--- a/client/app/hearings/components/VirtualHearingModal.jsx
+++ b/client/app/hearings/components/VirtualHearingModal.jsx
@@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react';
import _ from 'lodash';
import moment from 'moment-timezone';
-import { getAppellantTitleForHearing, zoneName } from '../utils';
+import { getAppellantTitle, zoneName } from '../utils';
import Button from '../../components/Button';
import COPY from '../../../COPY';
import Modal from '../../components/Modal';
@@ -71,7 +71,7 @@ export const ReadOnlyEmails = ({
appellantTzEdited,
showAllEmails = false,
}) => {
- const appellantTitle = getAppellantTitleForHearing(hearing);
+ const appellantTitle = getAppellantTitle(hearing?.appellantIsNotVeteran);
// Check for appellant edits
const appellantEdited = appellantTzEdited || appellantEmailEdited ?
@@ -201,7 +201,7 @@ export const ChangeToVirtual = (props) => {
const {
hearing, readOnly, representativeEmailError, update, appellantEmailError, virtualHearing
} = props;
- const appellantTitle = getAppellantTitleForHearing(hearing);
+ const appellantTitle = getAppellantTitle(hearing?.appellantIsNotVeteran);
// Prefill appellant/veteran email address and representative email on mount.
useEffect(() => {
@@ -327,7 +327,7 @@ const VirtualHearingModal = (props) => {
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false);
const typeSettings = TYPES[type];
- const appellantTitle = getAppellantTitleForHearing(hearing);
+ const appellantTitle = getAppellantTitle(hearing?.appellantIsNotVeteran);
const modalTitle = sprintf(
typeSettings.title({
representativeEmailEdited,
diff --git a/client/app/hearings/components/VirtualHearings/AppellantSection.jsx b/client/app/hearings/components/VirtualHearings/AppellantSection.jsx
index ee2bb8d05d9..b023fcbe36f 100644
--- a/client/app/hearings/components/VirtualHearings/AppellantSection.jsx
+++ b/client/app/hearings/components/VirtualHearings/AppellantSection.jsx
@@ -9,6 +9,7 @@ import { HelperText } from './HelperText';
import { VirtualHearingEmail } from './Emails';
import { Timezone } from './Timezone';
import { marginTop, noMaxWidth } from '../details/style';
+import { ReadOnly } from '../details/ReadOnly';
export const AppellantSection = ({
hearing,
@@ -18,50 +19,64 @@ export const AppellantSection = ({
virtual,
video,
readOnly,
+ showDivider,
update,
- appellantTitle
-}) => (
-
-
- {virtual && !video && (
-
+ appellantTitle,
+ showOnlyAppellantName
+}) => {
+ const appellantName = hearing?.appellantFullName ? hearing?.appellantFullName :
+ `${hearing?.veteranFirstName} ${hearing?.veteranLastName}`;
+
+ const showTimezoneField = virtual && !video;
+
+ return (
+
+ {showOnlyAppellantName ? (
+
+ ) :
+ (
+
+ )}
+ {showTimezoneField && (
+
+
+ update('virtualHearing', { appellantTz })}
+ time={hearing.scheduledTimeString}
+ name={`${appellantTitle} Timezone`}
+ errorMessage={errors?.appellantTz}
+ />
+
+
+
+ )}
+
- update('virtualHearing', { appellantTz })}
- time={hearing.scheduledTimeString}
- name={`${appellantTitle} Timezone`}
- errorMessage={errors?.appellantTz}
+ readOnly={readOnly}
+ label={`${appellantTitle} Email`}
+ emailType="appellantEmail"
+ email={virtualHearing?.appellantEmail}
+ error={errors?.appellantEmail}
+ type={type}
+ update={update}
/>
-
- )}
-
-
-);
+
+ );
+};
AppellantSection.propTypes = {
hearing: PropTypes.object,
@@ -72,5 +87,7 @@ AppellantSection.propTypes = {
virtual: PropTypes.bool,
video: PropTypes.bool,
readOnly: PropTypes.bool,
- appellantTitle: PropTypes.string
+ appellantTitle: PropTypes.string,
+ showOnlyAppellantName: PropTypes.bool,
+ showDivider: PropTypes.bool
};
diff --git a/client/app/hearings/components/VirtualHearings/RepresentativeSection.jsx b/client/app/hearings/components/VirtualHearings/RepresentativeSection.jsx
index 6dea5bee2fe..a396f622fa7 100644
--- a/client/app/hearings/components/VirtualHearings/RepresentativeSection.jsx
+++ b/client/app/hearings/components/VirtualHearings/RepresentativeSection.jsx
@@ -23,7 +23,7 @@ export const RepresentativeSection = ({
appellantTitle
}) => (
- {hearing.representative ? (
+ {hearing?.representative ? (
update('virtualHearing', { representativeTz })
}
- time={hearing.scheduledTimeString}
+ time={hearing?.scheduledTimeString}
name="POA/Representative Timezone"
/>
diff --git a/client/app/hearings/components/VirtualHearings/Section.jsx b/client/app/hearings/components/VirtualHearings/Section.jsx
index d58632737fb..340d221764e 100644
--- a/client/app/hearings/components/VirtualHearings/Section.jsx
+++ b/client/app/hearings/components/VirtualHearings/Section.jsx
@@ -1,10 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
-export const VirtualHearingSection = ({ label, children, hide }) =>
+import { marginTop } from '../details/style';
+
+export const VirtualHearingSection = ({ label, children, hide, showDivider }) =>
!hide && (
-
+ {showDivider ?
:
}
{label}
{children}
@@ -12,11 +14,13 @@ export const VirtualHearingSection = ({ label, children, hide }) =>
VirtualHearingSection.defaultProps = {
label: '',
- hide: false
+ hide: false,
+ showDivider: true
};
VirtualHearingSection.propTypes = {
children: PropTypes.node.isRequired,
label: PropTypes.string,
+ showDivider: PropTypes.bool,
hide: PropTypes.bool,
};
diff --git a/client/app/hearings/components/__snapshots__/HearingTypeConversionForm.test.js.snap b/client/app/hearings/components/__snapshots__/HearingTypeConversionForm.test.js.snap
new file mode 100644
index 00000000000..4bdeafad22f
--- /dev/null
+++ b/client/app/hearings/components/__snapshots__/HearingTypeConversionForm.test.js.snap
@@ -0,0 +1,699 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`HearingTypeConversionForm Does not show a divider on top of Appellant Section 1`] = `
+
+
+
+
+ Convert Hearing To Virtual
+
+ Nashville Regional office.",
+ }
+ }
+ />
+
+
+ Review and update the following information in VBMS if needed. Caseflow won't send email notifications until you schedule the hearing.
+
+
+
+
+
+
+ Veteran
+
+
+
+
+ Veteran Name
+
+
+ Abellona Valtas
+
+
+
+
+
+
+
+
+
+ Veteran Email
+
+
+ Abellona.Valtas@test.com
+
+
+
+
+
+
+
+
+
+
+
+
+ Power of Attorney
+
+
+
+
+
+ Attorney
+
+
+ Attorney McAttorneyFace
+
+
+
+
+
+
+
+
+
+
+
+ POA/Representative Email
+
+
+ tom.brady@caseflow.gov
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+ Convert Hearing To Virtual
+
+
+
+
+
+
+`;
+
+exports[`HearingTypeConversionForm Matches snapshot with default props 1`] = `
+
+
+
+
+ Convert Hearing To Virtual
+
+ Nashville Regional office.",
+ }
+ }
+ />
+
+
+ Review and update the following information in VBMS if needed. Caseflow won't send email notifications until you schedule the hearing.
+
+
+
+
+
+
+ Veteran
+
+
+
+
+ Veteran Name
+
+
+ Abellona Valtas
+
+
+
+
+
+
+
+
+
+ Veteran Email
+
+
+ Abellona.Valtas@test.com
+
+
+
+
+
+
+
+
+
+
+
+
+ Power of Attorney
+
+
+
+
+
+ Attorney
+
+
+ Attorney McAttorneyFace
+
+
+
+
+
+
+
+
+
+
+
+ POA/Representative Email
+
+
+ tom.brady@caseflow.gov
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+ Convert Hearing To Virtual
+
+
+
+
+
+
+`;
diff --git a/client/app/hearings/components/details/VirtualHearingForm.jsx b/client/app/hearings/components/details/VirtualHearingForm.jsx
index 07c7894d849..f619fe9578d 100644
--- a/client/app/hearings/components/details/VirtualHearingForm.jsx
+++ b/client/app/hearings/components/details/VirtualHearingForm.jsx
@@ -4,7 +4,7 @@ import React, { useContext, useEffect } from 'react';
import { ContentSection } from '../../../components/ContentSection';
import { HearingLinks } from './HearingLinks';
import { HearingsUserContext } from '../../contexts/HearingsUserContext';
-import { getAppellantTitleForHearing } from '../../utils';
+import { getAppellantTitle } from '../../utils';
import { VirtualHearingFields } from '../VirtualHearings/Fields';
export const VirtualHearingForm = (
@@ -17,7 +17,7 @@ export const VirtualHearingForm = (
// Hide the virtual hearing fields only when we are scheduling the virtual hearing
const showFields = (hearing?.isVirtual || hearing?.wasVirtual) && virtualHearing;
const readOnlyEmails = readOnly || !virtualHearing?.jobCompleted || hearing?.wasVirtual || hearing.scheduledForIsPast;
- const appellantTitle = getAppellantTitleForHearing(hearing);
+ const appellantTitle = getAppellantTitle(hearing?.appellantIsNotVeteran);
const user = useContext(HearingsUserContext);
useEffect(() => {
diff --git a/client/app/hearings/utils.js b/client/app/hearings/utils.js
index 8a740b7aafe..e2eb4024248 100644
--- a/client/app/hearings/utils.js
+++ b/client/app/hearings/utils.js
@@ -110,10 +110,10 @@ export const APPELLANT_TITLE = 'Appellant';
/**
* Gets the title to use for the appellant of a hearing.
- * @param {object} hearing -- A hearing
+ * @param {string} appellantIsNotVeteran -- bool
*/
-export const getAppellantTitleForHearing = (hearing) =>
- hearing?.appellantIsNotVeteran ? APPELLANT_TITLE : VETERAN_TITLE;
+export const getAppellantTitle = (appellantIsNotVeteran) =>
+ appellantIsNotVeteran ? APPELLANT_TITLE : VETERAN_TITLE;
export const VIRTUAL_HEARING_HOST = 'host';
export const VIRTUAL_HEARING_GUEST = 'guest';
diff --git a/client/app/queue/utils.js b/client/app/queue/utils.js
index 44ab0f2e31b..9780eb8ea02 100644
--- a/client/app/queue/utils.js
+++ b/client/app/queue/utils.js
@@ -330,6 +330,7 @@ export const prepareAppealForStore = (appeals) => {
veteranGender: appeal.attributes.veteran_gender,
veteranAddress: appeal.attributes.veteran_address,
closestRegionalOffice: appeal.attributes.closest_regional_office,
+ closestRegionalOfficeLabel: appeal.attributes.closest_regional_office_label,
availableHearingLocations: prepareAppealAvailableHearingLocationsForStore(appeal),
externalId: appeal.attributes.external_id,
status: appeal.attributes.status,
diff --git a/client/test/app/hearings/components/HearingConversion.test.js b/client/test/app/hearings/components/HearingConversion.test.js
index 7c408f8bdf3..e7deaf56fb0 100644
--- a/client/test/app/hearings/components/HearingConversion.test.js
+++ b/client/test/app/hearings/components/HearingConversion.test.js
@@ -13,7 +13,6 @@ import { JudgeDropdown } from 'app/components/DataDropdowns';
import { Timezone } from 'app/hearings/components/VirtualHearings/Timezone';
import RadioField from 'app/components/RadioField';
import { ReadOnly } from 'app/hearings/components/details/ReadOnly';
-import { getAppellantTitleForHearing } from 'app/hearings/utils';
import { defaultHearing } from 'test/data/hearings';
import { HearingLocationDropdown } from 'app/hearings/components/dailyDocket/DailyDocketRowInputs';
import { HearingTime } from 'app/hearings/components/modalForms/HearingTime';
diff --git a/client/test/app/hearings/components/VirtualHearings/RepresentativeSection.test.js b/client/test/app/hearings/components/VirtualHearings/RepresentativeSection.test.js
index 80b069871d9..21aa576bb80 100644
--- a/client/test/app/hearings/components/VirtualHearings/RepresentativeSection.test.js
+++ b/client/test/app/hearings/components/VirtualHearings/RepresentativeSection.test.js
@@ -10,7 +10,7 @@ import { AddressLine } from 'app/hearings/components/details/Address';
import { VirtualHearingEmail } from 'app/hearings/components/VirtualHearings/Emails';
import { Timezone } from 'app/hearings/components/VirtualHearings/Timezone';
import { ReadOnly } from 'app/hearings/components/details/ReadOnly';
-import { getAppellantTitleForHearing } from 'app/hearings/utils';
+import { getAppellantTitle } from 'app/hearings/utils';
import TextField from 'app/components/TextField';
const updateSpy = jest.fn();
@@ -92,7 +92,7 @@ describe('RepresentativeSection', () => {
expect(representativeSection.find(VirtualHearingSection).first().
find(ReadOnly).
prop('text')).toEqual(
- `The ${getAppellantTitleForHearing(amaHearing)} does not have a representative recorded in VBMS`
+ `The ${getAppellantTitle(amaHearing.appellantIsNotVeteran)} does not have a representative recorded in VBMS`
);
expect(representativeSection).toMatchSnapshot();
});
diff --git a/client/test/app/hearings/components/VirtualHearings/__snapshots__/AppellantSection.test.js.snap b/client/test/app/hearings/components/VirtualHearings/__snapshots__/AppellantSection.test.js.snap
index 0c0ce39076f..1b5be7adb01 100644
--- a/client/test/app/hearings/components/VirtualHearings/__snapshots__/AppellantSection.test.js.snap
+++ b/client/test/app/hearings/components/VirtualHearings/__snapshots__/AppellantSection.test.js.snap
@@ -114,6 +114,7 @@ exports[`Appellant Displays timezone when virtual 1`] = `
@@ -9129,6 +9132,7 @@ exports[`Details Displays HearingConversion when converting from video and featu
@@ -8651,6 +8654,7 @@ exports[`HearingConversion Matches snapshot with default props 1`] = `