Skip to content

Commit

Permalink
Appoint a rep - submission method (#34050)
Browse files Browse the repository at this point in the history
* Added feature toggle for appoint v2 features

* Moving page depends logic into schema files to clean up form config

* Made use of feature toggle for v2 features

* Adjusted feature toggle + env checks. Added constant for local testing without vets-api

* Created rep submission method screen

* Updated routing for to include submission method

* Added to submissionmethod page conditional

* Added unit tests for submission method

* Added return statement

* Disabled feature toggle for e2e tests

* comment

* Corrected error state copy

* Added unit test for error state

* File + component naming

* Updated pageDepends conditional

* Make use of new pagedepends in representativeSubmissionMethod
  • Loading branch information
cosu419 authored Jan 17, 2025
1 parent e00c7c5 commit 2d7bdb8
Show file tree
Hide file tree
Showing 13 changed files with 396 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import FormNavButtons from 'platform/forms-system/src/js/components/FormNavButto
import PropTypes from 'prop-types';
import { useReviewPage } from '../hooks/useReviewPage';
import { getEntityAddressAsObject } from '../utilities/helpers';
import useV2FeatureToggle from '../hooks/useV2FeatureVisibility';

import AddressEmailPhone from './AddressEmailPhone';

const ContactAccreditedRepresentative = props => {
const v2IsEnabled = useV2FeatureToggle();
const { formData, goBack, goForward, goToPath } = props;
const rep = props?.formData?.['view:selectedRepresentative'];
const repAttributes = rep?.attributes;
Expand All @@ -26,6 +28,9 @@ const ContactAccreditedRepresentative = props => {
) &&
representative.attributes?.accreditedOrganizations?.data?.length > 1;

// will need to update this when we can determine submission methods
const submissionMethodRequired = orgSelectionRequired && v2IsEnabled;

const handleGoBack = () => {
if (isReviewPage) {
goToPath('/representative-select?review=true');
Expand All @@ -36,6 +41,10 @@ const ContactAccreditedRepresentative = props => {

const handleGoForward = () => {
if (isReviewPage) {
if (submissionMethodRequired) {
goToPath('/representative-submission-method?review=true');
return;
}
if (orgSelectionRequired) {
goToPath('/representative-organization?review=true');
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { VaRadio } from '@department-of-veterans-affairs/component-library/dist/react-bindings';
import FormNavButtons from 'platform/forms-system/src/js/components/FormNavButtons';
import { scrollToFirstError } from 'platform/utilities/ui';
import { useReviewPage } from '../hooks/useReviewPage';

const RepresentativeSubmissionMethod = props => {
const { formData, setFormData, goBack, goForward, goToPath } = props;
const [error, setError] = useState(null);

const isReviewPage = useReviewPage();

const handleGoBack = () => {
if (isReviewPage) {
goToPath('representative-contact?review=true');
} else {
goBack(formData);
}
};
const handleGoForward = () => {
if (!formData?.representativeSubmissionMethod) {
setError('Choose how to submit your request by selecting an option');
scrollToFirstError({ focusOnAlertRole: true });
} else if (isReviewPage) {
goToPath('/representative-organization?review=true');
} else {
goForward(formData);
}
};

const handleRadioSelect = e => {
setError(null);
setFormData({
...formData,
representativeSubmissionMethod: e.detail.value,
});
};

return (
<>
<VaRadio
error={error}
label="Select how to submit your request"
required
onVaValueChange={handleRadioSelect}
>
<va-radio-option
label="Online"
name="method"
value="digital"
key={0}
checked={formData.representativeSubmissionMethod === 'digital'}
/>
<va-radio-option
label="By mail"
name="method"
value="mail"
key={1}
checked={formData.representativeSubmissionMethod === 'mail'}
/>
<va-radio-option
label="In person"
name="method"
value="in person"
key={2}
checked={formData.representativeSubmissionMethod === 'in person'}
/>
</VaRadio>
<FormNavButtons goBack={handleGoBack} goForward={handleGoForward} />
</>
);
};

RepresentativeSubmissionMethod.propTypes = {
formData: PropTypes.object,
goBack: PropTypes.func,
goForward: PropTypes.func,
goToPath: PropTypes.func,
setFormData: PropTypes.func,
};

function mapStateToProps(state) {
return {
formData: state.form.data,
};
}

export { RepresentativeSubmissionMethod }; // Named export for testing

export default connect(
mapStateToProps,
null,
)(RepresentativeSubmissionMethod);
32 changes: 15 additions & 17 deletions src/applications/representative-appoint/config/form.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import commonDefinitions from 'vets-json-schema/dist/definitions.json';
// import environment from '@department-of-veterans-affairs/platform-utilities/environment';
// import profileContactInfo from 'platform/forms-system/src/js/definitions/profileContactInfo';
import FormFooter from 'platform/forms/components/FormFooter';

import GetFormHelp from '../components/GetFormHelp';
import configService from '../utilities/configService';
import manifest from '../manifest.json';
Expand Down Expand Up @@ -33,6 +32,7 @@ import {
replaceAccreditedRepresentative,
selectedAccreditedOrganizationId,
contactAccreditedRepresentative,
representativeSubmissionMethod,
} from '../pages';

// import initialData from '../tests/fixtures/data/test-data.json';
Expand All @@ -41,6 +41,7 @@ import SelectAccreditedRepresentative from '../components/SelectAccreditedRepres
import SelectedAccreditedRepresentativeReview from '../components/SelectAccreditedRepresentativeReview';
import ContactAccreditedRepresentative from '../components/ContactAccreditedRepresentative';
import SelectOrganization from '../components/SelectOrganization';
import RepresentativeSubmissionMethod from '../components/RepresentativeSubmissionMethod';

import SubmissionError from '../components/SubmissionError';

Expand Down Expand Up @@ -136,29 +137,26 @@ const formConfig = {
uiSchema: contactAccreditedRepresentative.uiSchema,
schema: contactAccreditedRepresentative.schema,
},
RepresentativeSubmissionMethod: {
title: 'Representative Submission Method',
path: 'representative-submission-method',
CustomPage: RepresentativeSubmissionMethod,
depends: formData =>
representativeSubmissionMethod.pageDepends(formData),
uiSchema: representativeSubmissionMethod.uiSchema,
schema: representativeSubmissionMethod.schema,
},
selectAccreditedOrganization: {
path: 'representative-organization',
title: 'Organization Select',
hideOnReview: true,
CustomPage: SelectOrganization,
depends: formData =>
!!formData['view:selectedRepresentative'] &&
['representative', 'veteran_service_officer'].includes(
formData['view:selectedRepresentative'].attributes
?.individualType,
) &&
formData['view:selectedRepresentative'].attributes
?.accreditedOrganizations?.data?.length > 1,
selectedAccreditedOrganizationId.pageDepends(formData),
uiSchema: selectedAccreditedOrganizationId.uiSchema,
schema: {
type: 'object',
properties: {
selectedAccreditedOrganizationId: {
type: 'string',
},
},
},
schema: selectedAccreditedOrganizationId.schema,
},

replaceAccreditedRepresentative: {
title: 'Representative Replace',
path: 'representative-replace',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// toggle this eg when testing PRs locally

export const enableV2FeaturesForLocalTesting = true;
26 changes: 11 additions & 15 deletions src/applications/representative-appoint/containers/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import formConfig from '../config/form';
import configService from '../utilities/configService';
import { getFormSubtitle } from '../utilities/helpers';

import useV2FeatureToggle from '../hooks/useV2FeatureVisibility';

function App({ loggedIn, location, children, formData, setFormData }) {
const subTitle = getFormSubtitle(formData);

Expand All @@ -25,6 +27,7 @@ function App({ loggedIn, location, children, formData, setFormData }) {
} = useFeatureToggle();

const appIsEnabled = useToggleValue(appToggleKey);
const v2FeatureToggle = useV2FeatureToggle();
const isProduction = window.Cypress || environment.isProduction();
const isAppToggleLoading = useToggleLoadingValue(appToggleKey);

Expand All @@ -40,6 +43,7 @@ function App({ loggedIn, location, children, formData, setFormData }) {
[pathname],
);

// dynamically updates the form subtitle to 21-22 or 21-22A
useEffect(
() => {
configService.setFormConfig({ subTitle });
Expand All @@ -50,26 +54,18 @@ function App({ loggedIn, location, children, formData, setFormData }) {

useEffect(
() => {
const defaultViewFields = {
const updatedFormData = {
...formData,
v2IsEnabled: v2FeatureToggle,
'view:isLoggedIn': loggedIn,
'view:representativeQueryInput': '',
'view:representativeSearchResults': [],
};
setFormData({
...formData,
...defaultViewFields,
});
setFormData(updatedFormData);
},
[loggedIn],
[v2FeatureToggle, loggedIn],
);

// resetting user query between sessions
useEffect(() => {
setFormData({
...formData,
'view:representativeQueryInput': '',
'view:representativeSearchResults': [],
});
}, []);

if (isAppToggleLoading) {
return (
<div className="vads-u-margin-y--5">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useFeatureToggle } from '~/platform/utilities/feature-toggles';
import environment from 'platform/utilities/environment';
import { enableV2FeaturesForLocalTesting } from '../constants/enableV2FeaturesLocally';

const useV2FeatureToggle = () => {
const {
TOGGLE_NAMES: { appointARepresentativeEnableV2Features: appToggleKey },
useToggleLoadingValue,
useToggleValue,
} = useFeatureToggle();

const appointV2FeaturesEnabled = useToggleValue(appToggleKey);
const toggleIsLoading = useToggleLoadingValue(appToggleKey);

if (toggleIsLoading) {
return false;
}

// can remove this after verifying the toggle in staging
if (environment.isProduction() || window.Cypress) {
return false;
}

if (environment.isLocalhost()) {
return enableV2FeaturesForLocalTesting;
}

return appointV2FeaturesEnabled;
};

export default useV2FeatureToggle;
2 changes: 2 additions & 0 deletions src/applications/representative-appoint/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import * as selectAccreditedRepresentative from './representative/selectAccredit
import * as replaceAccreditedRepresentative from './representative/replaceAccreditedRepresentative';
import * as selectedAccreditedOrganizationId from './representative/selectAccreditedOrganization';
import * as contactAccreditedRepresentative from './representative/contactAccreditedRepresentative';
import * as representativeSubmissionMethod from './representative/representativeSubmissionMethod';

export {
authorizeMedical,
Expand All @@ -44,4 +45,5 @@ export {
replaceAccreditedRepresentative,
selectedAccreditedOrganizationId,
contactAccreditedRepresentative,
representativeSubmissionMethod,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import RepresentativeSubmissionMethod from '../../components/RepresentativeSubmissionMethod';

export const uiSchema = {
representativeSubmissionMethod: {
'ui:title': "Select how you'd like to submit your request",
'ui:widget': RepresentativeSubmissionMethod,
'ui:options': {
hideLabelText: true,
hideOnReview: true,
},
'ui:required': () => true,
},
};

export const schema = {
type: 'object',
properties: {
representativeSubmissionMethod: {
type: 'string',
},
},
};

export const pageDepends = formData => {
const { v2IsEnabled } = formData;
// temporarily hardcoding these values
const repHasMultipleOrganizations =
!!formData['view:selectedRepresentative'] &&
['representative', 'veteran_service_officer'].includes(
formData['view:selectedRepresentative'].attributes?.individualType,
) &&
formData['view:selectedRepresentative'].attributes?.accreditedOrganizations
?.data?.length > 1;
const userCanSubmitDigitally = true;
const representativeAcceptsDigitalSubmission = true;

return (
v2IsEnabled &&
repHasMultipleOrganizations &&
userCanSubmitDigitally &&
representativeAcceptsDigitalSubmission
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,22 @@ export const uiSchema = {
},
};

export const schema = {};
export const schema = {
type: 'object',
properties: {
selectedAccreditedOrganizationId: {
type: 'string',
},
},
};

export const pageDepends = formData => {
return (
!!formData['view:selectedRepresentative'] &&
['representative', 'veteran_service_officer'].includes(
formData['view:selectedRepresentative'].attributes?.individualType,
) &&
formData['view:selectedRepresentative'].attributes?.accreditedOrganizations
?.data?.length > 1
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ describe('Authenticated', () => {
data: {
features: [
{ name: 'appoint_a_representative_enable_frontend', value: true },
{
name: 'appoint_a_representative_enable_v2_features',
value: false,
},
],
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ describe('Unauthenticated', () => {
data: {
features: [
{ name: 'appoint_a_representative_enable_frontend', value: true },
{
name: 'appoint_a_representative_enable_v2_features',
value: false,
},
],
},
});
Expand Down
Loading

0 comments on commit 2d7bdb8

Please sign in to comment.