diff --git a/package.json b/package.json
index c80839407e78..ea808eb074a0 100644
--- a/package.json
+++ b/package.json
@@ -397,9 +397,11 @@
"src/platform/mhv",
"src/applications/check-in",
"src/applications/vaos",
- "src/applications/claims-status"
+ "src/applications/claims-status",
+ "src/applications/accredited-representative-portal/accreditation/21a"
],
"nohoist": [
+ "**/applications/accredited-representative-portal/accreditation/21a/react-router",
"**/applications-check-in/i18next-resources-to-backend",
"**/applications-check-in/react-i18next",
"**/applications-claims-status/@department-of-veterans-affairs/component-library",
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/README.md b/src/applications/accredited-representative-portal/accreditation/21a/README.md
index 75791c87975e..aa17a1dea197 100644
--- a/src/applications/accredited-representative-portal/accreditation/21a/README.md
+++ b/src/applications/accredited-representative-portal/accreditation/21a/README.md
@@ -1,6 +1,2 @@
### 🚨WIP Status and Dependency on the `representative` Application🚨
-This sub-application is incomplete and its development has been paused. It is almost dependency-free from the `representative` application that it might eventually live under except for the following imports:
-- `Header`
-- `Footer`
-- `createReduxStore`
-- `SIGN_IN_URL`
+This sub-application is incomplete and its development has been paused. It is dependency-free from the `representative` application that it might eventually live under.
\ No newline at end of file
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/app-entry.jsx b/src/applications/accredited-representative-portal/accreditation/21a/app-entry.jsx
index be0f5896eefa..a0c15824acd3 100644
--- a/src/applications/accredited-representative-portal/accreditation/21a/app-entry.jsx
+++ b/src/applications/accredited-representative-portal/accreditation/21a/app-entry.jsx
@@ -12,7 +12,7 @@ import './sass/21a.scss';
import manifest from './manifest.json';
import routes from './routes';
-import createReduxStore from '../../store';
+import createReduxStore from './store';
import rootReducer from './reducers';
window.appName = manifest.entryName;
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/components/common/Footer/Footer.jsx b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Footer/Footer.jsx
new file mode 100644
index 000000000000..421e253c838e
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Footer/Footer.jsx
@@ -0,0 +1,77 @@
+import React from 'react';
+import { replaceWithStagingDomain } from '~/platform/utilities/environment/stagingDomains';
+
+const Footer = () => {
+ return (
+
+
+
+
+
+
+ Looking for U.S. government information and services? Visit{' '}
+
+ USA.gov
+
+
+
+
+
+ );
+};
+
+export default Footer;
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/Header.jsx b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/Header.jsx
new file mode 100644
index 000000000000..1e0fc944589b
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/Header.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+
+import MobileHeader from './MobileHeader/MobileHeader';
+import WiderThanMobileHeader from './WiderThanMobileHeader/WiderThanMobileHeader';
+
+import './Header.scss';
+
+const Header = () => {
+ return (
+
+ );
+};
+
+export default Header;
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/Header.scss b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/Header.scss
new file mode 100644
index 000000000000..5b3c7217e051
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/Header.scss
@@ -0,0 +1,106 @@
+@import "~@department-of-veterans-affairs/css-library/dist/tokens/scss/variables";
+@import "~@department-of-veterans-affairs/css-library/dist/stylesheets/mixins";
+
+.arp-header {
+ min-height: 78px;
+
+ @media (min-width: $medium-screen) {
+ min-height: 98px;
+ }
+
+ .va-header-logo-wrapper {
+ display: flex;
+ align-items: center;
+ }
+
+ .user-nav {
+ white-space: nowrap;
+
+ .loading-icon-container {
+ color: var(--vads-color-white);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-grow: 1;
+ }
+
+ .icon {
+ width: 26px;
+ height: 24px;
+ }
+
+ .user-dropdown-email {
+ margin-left: 4px;
+ display: block;
+ max-width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ }
+
+ .mobile {
+ .header-us-flag {
+ height: 20px;
+ }
+
+ .expand-official-govt-explanation {
+ font-size: 12px;
+ }
+
+ .govt-expanded-arrow {
+ transform: rotate(180deg);
+ transform-origin: 50% 50%;
+ }
+
+ .va-crisis-line-container {
+ margin: 0px;
+ }
+
+ .arp-logo {
+ width: 320px;
+ }
+
+ .user-nav {
+ margin-left: 10px;
+
+ .user-dropdown-email {
+ max-width: 64px;
+ }
+ }
+
+ @media (min-width: $medium-screen) {
+ display: none !important;
+ }
+ }
+
+ .wider-than-mobile {
+ display: none;
+
+ @media (min-width: $medium-screen) {
+ display: block;
+
+ .arp-logo {
+ width: 480px;
+ }
+
+ .vet-toolbar {
+ display: flex;
+ justify-content: flex-end;
+ flex: 0 1 300px;
+
+ .user-nav {
+ margin-inline: 10px;
+
+ .loading-icon-container {
+ width: 88px;
+ }
+ }
+ }
+
+ .va-header-logo-menu {
+ padding-left: 10px;
+ }
+ }
+ }
+}
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/MobileHeader/MobileHeader.jsx b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/MobileHeader/MobileHeader.jsx
new file mode 100644
index 000000000000..a231e76d0408
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/MobileHeader/MobileHeader.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+
+import MobileOfficialGovtWebsite from './MobileOfficialGovtWebsite';
+import MobileLogoRow from './MobileLogoRow';
+
+const MobileHeader = () => {
+ return (
+
+ );
+};
+
+export default MobileHeader;
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/MobileHeader/MobileLogoRow.jsx b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/MobileHeader/MobileLogoRow.jsx
new file mode 100644
index 000000000000..63be5ee2f8dc
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/MobileHeader/MobileLogoRow.jsx
@@ -0,0 +1,38 @@
+import React from 'react';
+
+import UserNav from '../common/UserNav';
+
+export const MobileLogoRow = () => {
+ return (
+
+
+
+ );
+};
+
+export default MobileLogoRow;
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/MobileHeader/MobileOfficialGovtWebsite.jsx b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/MobileHeader/MobileOfficialGovtWebsite.jsx
new file mode 100644
index 000000000000..0e08e4c815cd
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/MobileHeader/MobileOfficialGovtWebsite.jsx
@@ -0,0 +1,96 @@
+import React, { useState } from 'react';
+import recordEvent from '~/platform/monitoring/record-event';
+
+export const MobileOfficialGovtWebsite = () => {
+ const [expanded, setExpanded] = useState(false);
+
+ const onToggle = () => {
+ if (expanded) {
+ recordEvent({ event: 'int-accordion-collapse' });
+ } else {
+ recordEvent({ event: 'int-accordion-expand' });
+ }
+
+ setExpanded(!expanded);
+ };
+
+ return (
+
+ {/* Banner */}
+
+
+ {/* eslint-disable-next-line @department-of-veterans-affairs/prefer-button-component */}
+
+ An official website of the United States government.
+
+
+
+
+
+ {/* Expanded section */}
+ {expanded && (
+
+
+
+
+ The .gov means it’s official.
+
+ Federal government websites often end in .gov or .mil. Before
+ sharing sensitive information, make sure you’re on a federal
+ government site.
+
+
+
+
+
+ The site is secure.
+ The https:// ensures that you’re
+ connecting to the official website and that any information you
+ provide is encrypted and sent securely.
+
+
+
+ )}
+
+ );
+};
+
+export default MobileOfficialGovtWebsite;
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/WiderThanMobileHeader/WiderThanMobileHeader.jsx b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/WiderThanMobileHeader/WiderThanMobileHeader.jsx
new file mode 100644
index 000000000000..7f9d789e376f
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/WiderThanMobileHeader/WiderThanMobileHeader.jsx
@@ -0,0 +1,19 @@
+import React from 'react';
+
+import WiderThanMobileLogoRow from './WiderThanMobileLogoRow';
+import WiderThanMobileOfficialGovtWebsite from './WiderThanMobileOfficialGovtWebsite';
+
+const WiderThanMobileHeader = () => {
+ return (
+
+ );
+};
+
+export default WiderThanMobileHeader;
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/WiderThanMobileHeader/WiderThanMobileLogoRow.jsx b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/WiderThanMobileHeader/WiderThanMobileLogoRow.jsx
new file mode 100644
index 000000000000..429ab16aab3c
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/WiderThanMobileHeader/WiderThanMobileLogoRow.jsx
@@ -0,0 +1,35 @@
+import React from 'react';
+
+import UserNav from '../common/UserNav';
+
+const WiderThanMobileLogoRow = () => {
+ return (
+
+ );
+};
+
+export default WiderThanMobileLogoRow;
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/WiderThanMobileHeader/WiderThanMobileOfficialGovtWebsite.jsx b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/WiderThanMobileHeader/WiderThanMobileOfficialGovtWebsite.jsx
new file mode 100644
index 000000000000..b6cdc1c60616
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/WiderThanMobileHeader/WiderThanMobileOfficialGovtWebsite.jsx
@@ -0,0 +1,82 @@
+import React, { useState } from 'react';
+
+const WiderThanMobileOfficialGovtWebsite = () => {
+ const [isExpanded, setIsExpanded] = useState(false);
+
+ const toggleExpansion = () => {
+ setIsExpanded(!isExpanded);
+ };
+ return (
+
+
+
+
+
+
+
An official website of the United States government
+ {/* eslint-disable-next-line @department-of-veterans-affairs/prefer-button-component, react/button-has-type */}
+
+
+ Here’s how you know
+
+
+
+
+
+
+
+
+
+ The .gov means it’s official.
+
+ Federal government websites often end in .gov or .mil. Before
+ sharing sensitive information, make sure you’re on a federal
+ government site.
+
+
+
+
+
+
+
+ The site is secure.
+ The https:// ensures that you’re
+ connecting to the official website and that any information you
+ provide is encrypted and sent securely.
+
+
+
+
+
+
+ );
+};
+
+export default WiderThanMobileOfficialGovtWebsite;
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/common/UserNav.jsx b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/common/UserNav.jsx
new file mode 100644
index 000000000000..2c26fd354adc
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/components/common/Header/common/UserNav.jsx
@@ -0,0 +1,141 @@
+import React, { useState, useRef, useEffect } from 'react';
+import { useSelector } from 'react-redux';
+import PropTypes from 'prop-types';
+
+import { SIGN_IN_URL, SIGN_OUT_URL } from '../../../../constants';
+import {
+ selectUserProfile,
+ selectIsUserLoading,
+} from '../../../../selectors/user';
+
+const generateUniqueId = () =>
+ `account-menu-${Math.random()
+ .toString(36)
+ .substring(2, 11)}`;
+
+const UserNav = ({ isMobile }) => {
+ const profile = useSelector(selectUserProfile);
+ const isLoading = useSelector(selectIsUserLoading);
+ const uniqueId = useRef(generateUniqueId());
+
+ const [isDropdownOpen, setDropdownOpen] = useState(false);
+ const dropdownRef = useRef(null);
+
+ const toggleDropdown = () => setDropdownOpen(!isDropdownOpen);
+
+ useEffect(
+ () => {
+ const handleClickOutside = event => {
+ if (
+ dropdownRef.current &&
+ !dropdownRef.current.contains(event.target)
+ ) {
+ setDropdownOpen(false);
+ }
+ };
+
+ if (isDropdownOpen) {
+ document.addEventListener('mousedown', handleClickOutside);
+ }
+
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside);
+ };
+ },
+ [isDropdownOpen],
+ );
+
+ let content;
+ if (isLoading) {
+ content = (
+
+
+
+ );
+ } else if (!profile && isMobile) {
+ content = (
+
+ Sign in
+
+ );
+ } else if (!profile && !isMobile) {
+ content = (
+
+ Sign in
+
+ );
+ } else if (profile) {
+ content = (
+
+ {/* eslint-disable-next-line @department-of-veterans-affairs/prefer-button-component */}
+
+
+
+
+
+
+ {`${profile.firstName}${isMobile ? '' : ` ${profile.lastName}`}`}
+
+
+
+
+
+ );
+ }
+
+ return {content}
;
+};
+
+UserNav.propTypes = {
+ isLoading: PropTypes.bool,
+ isMobile: PropTypes.bool,
+ profile: PropTypes.shape({
+ firstName: PropTypes.string,
+ lastName: PropTypes.string,
+ }),
+};
+
+export default UserNav;
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/constants/index.js b/src/applications/accredited-representative-portal/accreditation/21a/constants/index.js
new file mode 100644
index 000000000000..d999604373a3
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/constants/index.js
@@ -0,0 +1,18 @@
+import * as SIS from './sis';
+import * as USIP from './usip';
+
+export const SIGN_IN_URL = (() => {
+ const url = new URL(USIP.PATH, USIP.BASE_URL);
+ url.searchParams.set(USIP.QUERY_PARAMS.application, USIP.APPLICATIONS.ARP);
+ url.searchParams.set(USIP.QUERY_PARAMS.OAuth, true);
+ return url;
+})();
+
+export const SIGN_OUT_URL = (() => {
+ const url = new URL(SIS.API_URL({ endpoint: 'logout' }));
+ url.searchParams.set(
+ SIS.QUERY_PARAM_KEYS.CLIENT_ID,
+ sessionStorage.getItem('ci'),
+ );
+ return url;
+})();
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/constants/sis.js b/src/applications/accredited-representative-portal/accreditation/21a/constants/sis.js
new file mode 100644
index 000000000000..edc0e4a41c20
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/constants/sis.js
@@ -0,0 +1,9 @@
+export {
+ API_SIGN_IN_SERVICE_URL as API_URL,
+ CLIENT_IDS,
+ OAUTH_KEYS as QUERY_PARAM_KEYS,
+} from '~/platform/utilities/oauth/constants';
+
+export {
+ logoutUrlSiS as getLogoutUrl,
+} from '~/platform/utilities/oauth/utilities';
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/constants/usip.js b/src/applications/accredited-representative-portal/accreditation/21a/constants/usip.js
new file mode 100644
index 000000000000..418e80d4161d
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/constants/usip.js
@@ -0,0 +1,12 @@
+import environment from '@department-of-veterans-affairs/platform-utilities/environment';
+
+// To keep isolated application status, this is hardcoded rather than cross-app
+// imported from `login/manifest.json`.
+// https://depo-platform-documentation.scrollhelp.site/developer-docs/how-to-add-your-application-to-the-allow-list
+export const PATH = '/sign-in';
+export const { BASE_URL } = environment;
+
+export {
+ AUTH_PARAMS as QUERY_PARAMS,
+ EXTERNAL_APPS as APPLICATIONS,
+} from 'platform/user/authentication/constants';
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/containers/App.jsx b/src/applications/accredited-representative-portal/accreditation/21a/containers/App.jsx
index fe8d1763307d..f4a1e333fd47 100644
--- a/src/applications/accredited-representative-portal/accreditation/21a/containers/App.jsx
+++ b/src/applications/accredited-representative-portal/accreditation/21a/containers/App.jsx
@@ -6,9 +6,9 @@ import { VaLoadingIndicator } from '@department-of-veterans-affairs/component-li
import environment from '@department-of-veterans-affairs/platform-utilities/environment';
import { useFeatureToggle } from '~/platform/utilities/feature-toggles/useFeatureToggle';
-import Footer from '../../../components/common/Footer/Footer';
-import Header from '../../../components/common/Header/Header';
-import { SIGN_IN_URL } from '../../../constants';
+import Footer from '../components/common/Footer/Footer';
+import Header from '../components/common/Header/Header';
+import { SIGN_IN_URL } from '../constants';
import { fetchUser } from '../actions/user';
import { selectIsUserLoading } from '../selectors/user';
import { selectShouldGoToSignIn } from '../selectors/navigation';
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/containers/IntroductionPage.jsx b/src/applications/accredited-representative-portal/accreditation/21a/containers/IntroductionPage.jsx
index 9b9400a1ffc2..0dd3f5466c2a 100644
--- a/src/applications/accredited-representative-portal/accreditation/21a/containers/IntroductionPage.jsx
+++ b/src/applications/accredited-representative-portal/accreditation/21a/containers/IntroductionPage.jsx
@@ -5,7 +5,7 @@ import { useSelector } from 'react-redux';
import FormTitle from 'platform/forms-system/src/js/components/FormTitle';
import SaveInProgressIntro from 'platform/forms/save-in-progress/SaveInProgressIntro';
import { focusElement } from 'platform/utilities/ui';
-import { SIGN_IN_URL } from '../../../constants';
+import { SIGN_IN_URL } from '../constants';
import { selectIsUserLoggedIn } from '../selectors/user';
const SIGN_IN_LINK_PROPS = {
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/package.json b/src/applications/accredited-representative-portal/accreditation/21a/package.json
new file mode 100644
index 000000000000..03e8e4c70420
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "@department-of-veterans-affairs/applications-accredited-representative-portal-21",
+ "version": "1.0.0",
+ "private": true,
+ "dependencies": {
+ "react-router": "3.2.0",
+ "history": "3.0.0"
+ }
+}
diff --git a/src/applications/accredited-representative-portal/accreditation/21a/store.js b/src/applications/accredited-representative-portal/accreditation/21a/store.js
new file mode 100644
index 000000000000..b14d812afb76
--- /dev/null
+++ b/src/applications/accredited-representative-portal/accreditation/21a/store.js
@@ -0,0 +1,18 @@
+import { createStore, applyMiddleware, compose } from 'redux';
+import thunk from 'redux-thunk';
+import environment from '@department-of-veterans-affairs/platform-utilities/environment';
+
+const createReduxStore = rootReducer => {
+ const useDevTools =
+ !environment.isProduction() && window.__REDUX_DEVTOOLS_EXTENSION__;
+
+ return createStore(
+ rootReducer,
+ compose(
+ applyMiddleware(thunk),
+ useDevTools ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f,
+ ),
+ );
+};
+
+export default createReduxStore;