# APPEALS-23493: Reusability of Power of Attorney Details component
## Section 1: Goals of the research
- Goal 1: Determine the difficulty of reuse of the existing PoA component from the case details page
- Goal 2: Determine the workings of the component and it's relevant controllers, actions, and models.
- Goal 3: Determine possible implemenations or issues that need to be answered for this work to occur
## Section 2: Details and Implementation
### Subsection 2.1: Details
Link to the testing github branch: [Appeals-23493 Research](https://github.com/department-of-veterans-affairs/caseflow/tree/TYLERB/APPEALS-23493-Research)
The existing component from the case details page is named PowerOfAttorneyDetail.jsx. The task is to see if the component can be placed into a new section of the app, specifically the decision review queue's Task Page or disposition instead of the Case Details page in queue.
Here are some of the relevant files that we will be looking at and modifying:
* The main component file: [PoADetails](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/queue/PowerOfAttorneyDetail.jsx)
* The place where we might place the component. Either the [Disposition file](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/nonComp/components/Disposition.jsx) or the [TaskPage file](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/nonComp/pages/TaskPage.jsx)
* The appeals controller [Appeals Controller file](https://github.com/department-of-veterans-affairs/caseflow/blob/master/app/controllers/appeals_controller.rb)
* The noncomp index.js file [NonComp Index](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/nonComp/index.jsx)
* The [Higher Level Review](https://github.com/department-of-veterans-affairs/caseflow/blob/master/app/models/higher_level_review.rb) and [Supplemental Claim](https://github.com/department-of-veterans-affairs/caseflow/blob/master/app/models/supplemental_claim.rb) model files
* Possibly more including some erb files in noncomp/decision review
The component works through api calls using the redux state via redux selectors. Therefore, in order to plug and play this component into our section of the app, we would need to either implement those or reuse them from the queue component.
Some of the possible steps will be outlined below in the implementation section that could accomplish this.
### Subsection 2.2: Implementation
#### Subsection 2.2.1: Adding the Component to Disposition
First thing is first. Here's how the component is currently used in case details. [CaseDetailsView.jsx](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/queue/CaseDetailsView.jsx)
```jsx
<PowerOfAttorneyDetail
title={CASE_DETAILS_POA_SUBSTITUTE}
appealId={appealId}
additionalHeaderContent={
editPOAInformation && (
<span
className="cf-push-right"
{...editAppellantInformationLinkStyling}
>
<Link to={`/queue/appeals/${appealId}/edit_poa_information`}>
{updatePOALink}
</Link>
</span>
)
}
/>
```
And here is what it looks like on the page

So we need to transplant this into our decision review queue page. The designs show it on the Disposition page so we will place it there. However, it should probably go in the TaskPage which would also include RecordRequests and BoardGrants. That's a question that needs to be answered before the actual implementation.
So in Disposition.jsx let's throw our component in there.
```jsx
return <div>
<PowerOfAttorneyDetail
title={COPY.CASE_DETAILS_POA_SUBSTITUTE}
appealId={appealId}
additionalHeaderContent={
editPOAInformation && (
<div>
<h3>Something?</h3>
<span
className="cf-push-right"
{...editAppellantInformationLinkStyling}
>
<Link to={`/queue/appeals/${appealId}/edit_poa_information`}>
{updatePOALink}
</Link>
</span></div>
)
}
/>
<div>
<div className="cf-decisions">
<div className="usa-grid-full">
<div className="usa-width-one-half">
<h2>Decision</h2>
<div>Review each issue and assign the appropriate dispositions.</div>
</div>
<div className="usa-width-one-half cf-txt-r">
{editIssuesLink}
</div>
</div>
<div className="cf-decision-list">
```
This component also needs some setup before it is used. It needs to be imported and it expects a few variables if we reuse the same component properties
```jsx
// Import the component at the top of the page
import PowerOfAttorneyDetail from '../../queue/PowerOfAttorneyDetail';
// Before the component is used some of these need to be established to pass them as props to PowerOfAttorneyDetail
// These two are copied from case details and are styling and link text. They could easily be adjusted to what we want
const editAppellantInformationLinkStyling = css({
fontSize: '2rem',
fontWeight: 'normal',
margin: '5px',
});
const updatePOALink = appeal.hasPOA ? COPY.EDIT_APPELLANT_INFORMATION_LINK : COPY.UP_DATE_POA_LINK;
// This is the real editPOAInformation from case details
// const editPOAInformation =
// props.userCanEditUnrecognizedPOA &&
// [APPELLANT_TYPES.OTHER_CLAIMANT, APPELLANT_TYPES.HEALTHCARE_PROVIDER_CLAIMANT].includes(
// appeal.appellantType
// ) && !appeal.hasPOA && props.featureToggles.edit_unrecognized_appellant_poa;
//
// Just set it to true for now to always show the button
const editPOAInformation = true;
// The appeal uuid that the PoA component uses to fetch the poa information from the backend
const appealId = task.appeal.uuid;
```
Currently on the disposition page, the task.appeal information does not include uuid so we need to add it to the [decision_review_task_serializer.rb](https://github.com/department-of-veterans-affairs/caseflow/blob/master/app/models/serializers/work_queue/decision_review_task_serializer.rb)
It would probably also mean updating the serializer test eventually as well but we will irnogre that for now.
```ruby
attribute :appeal do |object|
# If :issue_count is present then we're hitting this serializer from a Decision Review
# queue table, and we do not need to gather request issues as they are not used there.
skip_acquiring_request_issues = object[:issue_count]
{
id: decision_review(object).external_id,
uuid: decision_review(object).uuid,
isLegacyAppeal: false,
issueCount: issue_count(object),
activeRequestIssues: skip_acquiring_request_issues || request_issues(object).active.map(&:serialize)
}
end
```
Now everything should be setup on the disposition page for the PowerOfAttorneyDetail component to show up. However, it will error until the redux state is setup properly.
#### Subsection 2.2.2: Setting up the component to work in the decision review/non comp section of the app
There are probably 3 possible paths to getting this component to work in the decision review queue:
* Implement it the same as how it works on the queue app in the Case Details Page. This means setting up all of the redux store, actions, and reducers from queue to make this work.
* Only import the UnconnectedPowerOfAttorney component and directly use it based on properties returned from the intial page load
* A hybrid approach where we use the intial page load data to setup the redux store.
The first approach is what I went with for this example.
So in order to start with this approach, the redux store will need to be in the proper state that it expects.
In the NonComp [Index.jsx](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/nonComp/index.jsx) file
```jsx
// This line sets up our initial state from the props based up from server erb files
const initialState = mapDataToInitialState(this.props);
```
This line sets up our redux store to be in the form of a toplevel hash with keys from the properties that come in from the server {key1: value1, key2: value2}
In the PoA Component Wrapper that retrieves the data from the backend we can follow it to see what information it needs but an easy way to do this would be to just copy the setup from the queue redux store
```jsx
// Import the initial setup from the queue redux store
// Also import the reducer for later
import { initialState as initialQueueReduxState, workQueueReducer } from '../queue/reducers';
import workQueueUiReducer, { initialState as initialUIReduxState } from '../queue/uiReducer/uiReducer';
```
Once these are imported we can use them to setup our state below
```jsx
// Add the initial queue redux state to our state that it expects so it doesn't throw errors when it tries to reference those values. It will all be undefined data but that's probably fine.
const initialState = mapDataToInitialState(this.props);
initialState.queue = initialQueueReduxState;
initialState.ui = initialUIReduxState;
```
To determine what fields we actually needed to be populated we could follow the logic in the const PowerOfAttorneyDetailWrapper component function in the PoADetails file.
It uses a couple of selectors and actions to retreive the appeal data from the redux store and if it isn't there then it goes to api/backend
```jsx
const wrappedComponent = ({ appealId, getAppealValue: getAppealValueRedux }) => {
const { error, loading, powerOfAttorney, appellantType } = useSelector(
powerOfAttorneyFromAppealSelector(appealId),
shallowEqual
);
// It also uses this selector that looks at the ui state so we need ui as well
const poaAlert = useSelector((state) => state.ui.poaAlert);
```
Specifically it uses getAppealValue action and powerOfAttorneyFromAppealSelector selector. These are chained so first we have to follow the getAppealValue action.
```jsx!
// In the poa component jsx file
import { getAppealValue } from './QueueActions';
// In QueueActions.js file
export const getAppealValue = (appealId, endpoint, name) => (dispatch) => {
dispatch({
type: ACTIONS.STARTED_LOADING_APPEAL_VALUE,
payload: {
appealId,
name
}
});
const urlString = `/appeals/${appealId}/${endpoint}`;
ApiUtil.get(urlString).then((response) => {
dispatch({
type: ACTIONS.RECEIVE_APPEAL_VALUE,
payload: {
appealId,
name,
response: response.body
}
});
}, (error) => {
dispatch({
type: ACTIONS.ERROR_ON_RECEIVE_APPEAL_VALUE,
payload: {
appealId,
name,
error
}
});
});
};
```
The most relevant parts of this action are:
```jsx
// The url that it will use to fetch from the endpoint
const urlString = `/appeals/${appealId}/${endpoint}`;
// The action constants that are being dispatched
ACTIONS.STARTED_LOADING_APPEAL_VALUE
ACTIONS.RECEIVE_APPEAL_VALUE
ACTIONS.ERROR_ON_RECEIVE_APPEAL_VALUE
```
We will worry about the url later. These constants are used as mappings to reducer functions that will be called asynchronously on the redux store with the retrieved/given payload.
In the [Queue Reducer](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/queue/reducers.js) file
```jsx!
// This maps our constant from the dispatch call to this function receiveAppealValue
export const workQueueReducer = createReducer({
[ACTIONS.RECEIVE_APPEAL_VALUE]: receiveAppealValue,
});
// The actual function that does the work
const receiveAppealValue = (state, action) => {
const existingState = state.loadingAppealDetail[action.payload.appealId] || {};
const existingDetails = state.appealDetails[action.payload.appealId] || {};
return update(state, {
loadingAppealDetail: {
$merge: {
[action.payload.appealId]: {
...existingState,
[action.payload.name]: {
loading: false
}
}
}
},
appealDetails: {
$merge: {
[action.payload.appealId]: {
...existingDetails,
[action.payload.name]: action.payload.response
}
}
}
});
};
```
Here we can see the two keys being updated in the redux store:
* loadingAppealDetail:
* appealDetails:
These are scoped to queue so it would be the equivilent of state.queue.loadingAppealDetail and state.queue.appealDetails
That is a lot of searching to figure out what keys are needed. Hence, why it was easier earlier to just copy the entire state setup.
So now that we know how this component wrapper works, we will need the queue reducer for sure if we want to use the wrapper in the same that the CaseDetails is using it.
Back in our index.js file for Noncomp. This could also be done in the noncomp reducers file and exported.
```jsx!
import { combineReducers } from 'redux';
// Have to combine the noncomp and queue reducers to get the functionality needed for PoA Details Component
const rootReducer = combineReducers({
queue: workQueueReducer,
nonComp: nonCompReducer
});
// Also add it to our Redux store or nothing will happen
<ReduxBase initialState={initialState} reducer={rootReducer}>
```
This is all the setup needed for the frontend to initial the api call. However, there is a side effect of using combineReducers in this way. Our noncomp state is now
```javascript
{
nonComp: {keys, values},
queue: {keys, values}
}
```
When before it was the top level scope of the state. So this will unfortunately break basically all the connect statements in NonComp so we have to go fix all of those.
[NonCompTabs](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/nonComp/components/NonCompTabs.jsx)
```jsx!
const NonCompTabs = connect(
(state) => ({
currentTab: state.nonComp.currentTab,
baseTasksUrl: state.nonComp.baseTasksUrl,
taskFilterDetails: state.nonComp.taskFilterDetails
})
)(NonCompTabsUnconnected);
```
[TaskTableTab](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/nonComp/components/TaskTableTab.jsx)
```jsx!
const TaskTableTab = connect(
(state) => ({
featureToggles: state.nonComp.featureToggles
})
)(TaskTableTabUnconnected);
```
[Disposition](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/nonComp/components/Disposition.jsx)
```jsx!
export default connect(
(state) => ({
appeal: state.nonComp.appeal,
task: state.nonComp.task,
decisionIssuesStatus: state.nonComp.decisionIssuesStatus
})
)(NonCompDispositions);
```
[BoardGrant](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/nonComp/components/BoardGrant.jsx)
```jsx!
const BoardGrant = connect(
(state) => ({
appeal: state.nonComp.appeal,
businessLine: state.nonComp.businessLine,
task: state.nonComp.task,
decisionIssuesStatus: state.nonComp.decisionIssuesStatus
})
)(BoardGrantUnconnected);
```
[Record Request](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/nonComp/components/RecordRequest.jsx)
```jsx!
const RecordRequest = connect(
(state) => ({
appeal: state.nonComp.appeal,
businessLine: state.nonComp.businessLine,
task: state.nonComp.task,
decisionIssuesStatus: state.nonComp.decisionIssuesStatus
})
)(RecordRequestUnconnected);
```
There could be a couple more but hopefully that's all. The component should be setup now to work using the redux store
The second type of implementation from the list of options would have looked more like this. In the disposition file we would import the unconnected component instead of the fully connected component. Of course it wouldn't work without fully supplying all of the data and the refresh button couldn't work either since it also relies on redux calls, but this is an option to consider.
```jsx!
import { PowerOfAttorneyDetailUnconnected } from '../../queue/PowerOfAttorneyDetail';
// It would need all of these properties since they weren't being retrieved from the backend in the same way as the Queue implementation
export const PowerOfAttorneyDetailUnconnected = ({ powerOfAttorney, appealId, poaAlert, appellantType });
```
This second method would probably the next section quite a bit less messy at the cost of more backend work. However, it might result in a cleaner implementation overall. We could also implement a new wrapper for the decision review redux store instead of using the built in wrapper present in the component for the queue redux store.
#### Subsection 2.2.3: Retrieving the information from the backend api
This section is largely dependent on how the data is retrieved from the backend by the frontend implementation. I'll outline the existing method that queue currently uses and how to work with that first.
```jsx!
// The url that it will use to fetch an appeal from the endpoint
// This is in the QueueAction getAppealValue
const urlString = `/appeals/${appealId}/${endpoint}`;
// This is how it builds the endpoint.
getAppealValueRedux(appealId, 'power_of_attorney', 'powerOfAttorney');
// So the resulting url will be /appeals/${appealID}/power_of_attorney
```
That url will be in the [routes.rb](https://github.com/department-of-veterans-affairs/caseflow/blob/master/config/routes.rb) file
```ruby!
resources :appeals, param: :appeal_id, only: [:index, :show, :edit] do
member do
get :document_count
get :veteran
get :power_of_attorney
patch :update_power_of_attorney
get 'hearings', to: "appeals#most_recent_hearing"
resources :issues, only: [:create, :update, :destroy], param: :vacols_sequence_id
resources :special_issues, only: [:create, :index]
resources :advance_on_docket_motions, only: [:create]
get 'tasks', to: "tasks#for_appeal"
patch 'update'
post 'work_mode', to: "work_modes#create"
patch 'cavc_remand', to: "cavc_remands#update"
post 'cavc_remand', to: "cavc_remands#create"
post 'appellant_substitution', to: "appellant_substitutions#create"
patch 'nod_date_update', to: "nod_date_updates#update"
end
end
# The actual part of the dsl we care about we care about
get :power_of_attorney
```
This will hit the [appeals_controller](https://github.com/department-of-veterans-affairs/caseflow/blob/master/app/controllers/appeals_controller.rb) at the action power_of_attorney
```ruby!
def power_of_attorney
render json: power_of_attorney_data
end
```
Which renders this json
```ruby!
def power_of_attorney_data
{
representative_type: appeal.representative_type,
representative_name: appeal.representative_name,
representative_address: appeal.representative_address,
representative_email_address: appeal.representative_email_address,
representative_tz: appeal.representative_tz,
poa_last_synced_at: appeal.poa_last_synced_at
}
end
```
Appeal is a cached attribute defined by this method
```ruby
def appeal
@appeal ||= Appeal.find_appeal_by_uuid_or_find_or_create_legacy_appeal_by_vacols_id(params[:appeal_id])
end
```
So this is already a problem. The decision review queue will be dealing with HigherLevelReviews and SupplmentalClaims instead of just Appeals.
And we are using the appeals_controller for things that aren't always going to be appeals. There are ways to get around this by just checking against the other types of decision reviews first either here or in that find method but it's not an ideal solution.
```ruby!
# We can hack the method to work for our types for now though
@appeal ||= (HigherLevelReview.find_by(uuid: params[:appeal_id]) || SupplementalClaim.find_by(uuid: params[:appeal_id]))
```
So now we have our decision review saved as the appeal variable.
Now the json method calls a bunch of methods on what it assumes is the appeal model. The HLR and SC model classes do not have most of these methods.
In the [Appeal](https://github.com/department-of-veterans-affairs/caseflow/blob/master/app/models/appeal.rb) model
```ruby!
delegate :power_of_attorney, to: :claimant
delegate :representative_name,
:representative_type,
:representative_address,
:representative_email_address,
:poa_last_synced_at,
:update_cached_attributes!,
:save_with_updated_bgs_record!,
to: :power_of_attorney, allow_nil: true
```
A lot of the call used for the json are delegated to the claimant association in the appeal model but that doesn't exist for our HLRs or SCs so we can add it for now
In the [HigherLevelReview] model
```ruby!
class HigherLevelReview < ClaimReview
with_options if: :saving_review do
validates :informal_conference, inclusion: { in: [true, false], message: "blank" }
validates :same_office, inclusion: { in: [true, false], message: "blank" },
unless: lambda {
FeatureToggle.enabled?(:updated_intake_forms, user: RequestStore.store[:current_user])
}
end
has_many :remand_supplemental_claims, as: :decision_review_remanded, class_name: "SupplementalClaim"
delegate :power_of_attorney, to: :claimant
delegate :representative_name,
:representative_type,
:representative_address,
:representative_email_address,
:poa_last_synced_at,
:update_cached_attributes!,
:save_with_updated_bgs_record!,
to: :power_of_attorney, allow_nil: true
# ... etc
```
There are two more methods in the json hash that are from the [AppealConcern](https://github.com/department-of-veterans-affairs/caseflow/blob/master/app/models/concerns/appeal_concern.rb) ActiveRecord Concern so we would need those too
```ruby!
# Borrowed from AppealConcern
def representative_tz
timezone_identifier_for_address(representative_address)
end
# Borrowed from AppealConcern
def timezone_identifier_for_address(addr)
return if addr.blank?
address_obj = addr.is_a?(Hash) ? Address.new(addr) : addr
# Some appellant addresses have empty country values but valid city, state, and zip codes.
# If the address has a zip code then we make the best guess that the address is within the US
# (TimezoneService.address_to_timezone will raise an error if this guess is wrong and the zip
# code is not a valid US zip code), otherwise we return nil without attempting to get
# thetimezone identifier.
if address_obj.country.blank?
return if address_obj.zip.blank?
new_address_hash = address_obj.as_json.symbolize_keys.merge(country: "USA")
address_obj = Address.new(**new_address_hash)
end
# APO/FPO/DPO addresses do not have time zones so we don't attempt to fetch them.
return if address_obj.military_or_diplomatic_address?
begin
TimezoneService.address_to_timezone(address_obj).identifier
rescue TimezoneService::AmbiguousTimezoneError => error
# TimezoneService raises an error for foreign countries that span multiple time zones since we
# only look up time zones by country for foreign addresses. We do not act on these errors (they
# are valid addresses, we just cannot determine the time zone) so we do not send the error to
# Sentry, only to Datadog for trend tracking.
DataDogService.increment_counter(
metric_group: "appeal_timezone_service",
metric_name: "ambiguous_timezone_error",
app_name: RequestStore[:application],
attrs: {
country_code: error.country_code
}
)
nil
rescue StandardError => error
Raven.capture_exception(error)
nil
end
end
```
Once those are in the redux retrieval should work and the component should be present on the Task page for a disposition.
The styling will have to be adjusted since the title doesn't get rendered by the component itself.

This implementation reuses the current redux and component wrapper. If we made our own wrapper or we went with the unconnected component implementation. We could place most of the controller logic in the decision review queue controller instead of the appeal controller. We could also maybe pass it a different getAppealValue function which would let us do the same thing. I think that's probably preferable to going through the appeals controller for things that aren't appeals.
Example of sending a different getAppealValue function
```jsx!
// In dispositions
<PowerOfAttorneyDetail
title={COPY.CASE_DETAILS_POA_SUBSTITUTE}
appealId={appealId}
// getAppealValueRedux={this.getAppealValueRedux}
getAppealValue={this.getAppealValueRedux}
//... etc more properties
// In PowerOfAttorneyDetail.jsx
import { getAppealValue as importedGetAppealValue } from './QueueActions';
const PowerOfAttorneyDetailWrapper = (WrappedComponent) => {
const wrappedComponent = ({ appealId, getAppealValue: getAppealValueRedux }) => {
const getAppealValue = getAppealValueRedux || importedGetAppealValue;
```
Example of new wrapper
```jsx!
// In our new wrapper file
import { getDecisionReviewValue } from './QueueActions';
const PowerOfAttorneyDetailDecisionReviewWrapper = (WrappedComponent) => {
// I hate this method of destructuring. It's so damn obfuscated unless you know the exact syntax of what is happening.
const wrappedComponent = ({ appealId, getDecisionReviewValue: ourNewFunction }) => {
//other setup etc...
// Our new function or action which would could send a request that hits the DR controller instead of the appeals controller
// example route: /decision_reviews/{appeal_id}/power_of_attorney
ourNewFunction(appealId)
}
```
#### Subsection 2.2.4: Setting up PoA Refresh button
The button is created via the [PoaRefresh.jsx](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/queue/components/PoaRefresh.jsx) component
It is added in the PoA component with these lines in the renderPoaLogic() function.
```jsx!
// both variables are setup like this
const isRecognizedAppellant = ![
APPELLANT_TYPES.OTHER_CLAIMANT,
APPELLANT_TYPES.ATTORNEY_CLAIMANT,
APPELLANT_TYPES.HEALTHCARE_PROVIDER_CLAIMANT
].includes(appellantType);
const isRecognizedPoa = poa.representative_type !== 'Unrecognized representative';
if (isRecognizedAppellant && isRecognizedPoa) {
return <PoaRefresh powerOfAttorney={poa} appealId={appealId}
{...detailListStyling}
/>;
}
```
Inside of the Poa Refresh component there seems to be a switch on a feature toggle to determine if the button should be shown or not
```jsx!
const viewPoaRefresh = useSelector((state) => state.ui.featureToggles.poa_button_refresh);
return <React.Fragment>
{viewPoaRefresh &&
<div {...textStyling}>
<em>{ COPY.CASE_DETAILS_POA_REFRESH_BUTTON_EXPLANATION }</em>
<div {...gutterStyling}></div>
<div {...boldText}{...syncStyling}>
{poaSyncInfo.poaSyncDate &&
<em>{lastSyncedCopy}</em>
}
<PoaRefreshButton appealId={appealId} />
</div>
</div>
}
</React.Fragment>;
```
This switch is based on a feature toggle in the ui state object. We are already passing up feature toggles in the index file in nonComp.js. It's easy enough add this feature toggle to the decision review [index.erb](https://github.com/department-of-veterans-affairs/caseflow/blob/master/app/views/decision_reviews/index.html.erb) and [show.html.erb](https://github.com/department-of-veterans-affairs/caseflow/blob/master/app/views/decision_reviews/show.html.erb)
```ruby
featureToggles: {
decisionReviewQueueSsnColumn: FeatureToggle.enabled?(:decision_review_queue_ssn_column, user: current_user),
poa_button_refresh: FeatureToggle.enabled?(:poa_button_refresh, user: current_user),
poa_auto_refresh: FeatureToggle.enabled?(:poa_auto_refresh, user: current_user)
},
```
Queue also has the poa_auto_refresh feature toggle. I am not sure what it does or if we want that as well.
Now we can just do a quick hack in the nonComp index.js file to copy these nonComp feature toggles to the ui feature toggles state. It could probably be a dispatch call using an ui action but it's easier for a demonstration to just add it to the initial state and we are already population noncomp state like that anyhow.
```jsx!
initialState.ui.featureToggles = this.props.serverNonComp.featureToggles;
```
After that the button should appear on the page in the component. Styling isn't perfect out of the box.

The actual button click and rendering is handled by a different component inside of PoaRefresh named [PoaRefreshButton](https://github.com/department-of-veterans-affairs/caseflow/blob/master/client/app/queue/components/PoaRefreshButton.jsx)
It uses the function below to update the PoA
```jsx!
const updatePOA = () => {
setButtonText(<SmallLoader message="Refresh POA" spinnerColor="#417505" />);
ApiUtil.patch(`/appeals/${appealId}/update_power_of_attorney`).then((data) => {
dispatch(setPoaRefreshAlert(data.body.alert_type, data.body.message, data.body.power_of_attorney));
setButtonText('Refresh POA');
});
};
```
It hits the appeals controller again, however this button currently has no way to change the url like the other component since the ApiUtil patch is written directly into the component. The updatePOA function would need to be passed as a function if we wanted to change that somehow.
Regardless of all that, it will currently hit the appeals controller on the action update_power_of_attorney
```ruby!
def update_power_of_attorney
clear_poa_not_found_cache
if cooldown_period_remaining > 0
render json: {
alert_type: "info",
message: "Information is current at this time. Please try again in #{cooldown_period_remaining} minutes",
power_of_attorney: power_of_attorney_data
}
else
message, result, status = update_or_delete_power_of_attorney!
render json: {
alert_type: result,
message: message,
power_of_attorney: (status == "updated") ? power_of_attorney_data : {}
}
end
rescue StandardError => error
render_error(error)
end
```
It will probably hit the else block first since it hasn't been updated for demo/local. Which means it will call the update_or_delete_power_of_attorney! method
```ruby!
def update_or_delete_power_of_attorney!
appeal.power_of_attorney&.try(:clear_bgs_power_of_attorney!) # clear memoization on legacy appeals
poa = appeal.bgs_power_of_attorney
if poa.blank?
["Successfully refreshed. No power of attorney information was found at this time.", "success", "blank"]
elsif poa.bgs_record == :not_found
poa.destroy!
["Successfully refreshed. No power of attorney information was found at this time.", "success", "deleted"]
else
poa.save_with_updated_bgs_record!
["POA Updated Successfully", "success", "updated"]
end
end
```
HLRs and SCs do not have this so we have to add it
```ruby!
# HLR/SC does not have this method so we have to add
poa = appeal.bgs_power_of_attorney
```
```ruby
def bgs_power_of_attorney
claimant&.is_a?(BgsRelatedClaimant) ? power_of_attorney : nil
end
```
After that the button click will work, but it will still error. However, the error is the normal BGS Postgres error for duplicate id meaning that it is probably working at this point. However the render_error method actually also breaks because the type method is missing from HLR/SC so add that too.
```ruby!
def type
"Original: Higher Level Review?"
end
```
Now the button should behaving the same in both the queue Case Details page and the decision review Disposition page.
**Note: I'm not sure how to make the actual Bgs call work, but I assume you would have to match the ids and participant ids to ones that you setup in the BGS fakes so it will properly update the information instead of forcing it into keys that will trigger a DB error.**
## Section 3: Results and Conclusions
### Subsection 3.1: Results
Reusing the component is not as straightforward as we might have initially hoped.
The implementation reusing component can be implemented in roughly 3 ways that are immediately apparent to me:
* Completely reuse the full redux implementation from queue
* Create a new wrapper to populate the PoA component from the noncomp redux store (Or it could still use the queue redux store. The main thing would be rerouting the api calls to the DR queue)
* Import the Component without a wrapper and get the information on initial page load (We could also get that information through redux calls or api calls that we create from scratch.)
No matter which method we go with, it will not be as quick as just placing the component on the page due all of the differences between the two frontend redux stores. The backend appeals controller also does not understand how to deal with decision reviews other than appeals (and rightfully so since it's the "APPEALS" controller).
### Subsection 3.2: Questions that need to be answered before or during implemenation
Here is a list of questions that might be nice to have some answers to before someone picks this up eventually.
1. Which method of frontend implementation we want to go with?
2. Do we want to tack this onto the appeals controller or reroute everything to the DR controller?
3. Should this component only be on the Dispositions page or should it also be on the other Task pages like Record Request and Board Grant?
4. Should we break this ticket up into front and backend after all since there is more work than previously thought.
5. How to actually setup the fake BGS service, so that we can actually test the refresh button correctly.