2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 Amdocs
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
21 import React, {Component} from 'react';
22 import { PropTypes } from 'prop-types';
23 import {connect} from 'react-redux';
24 import FontAwesome from 'react-fontawesome';
25 import {clearFilters} from 'filter-bar-utils';
26 import Button from 'react-bootstrap/lib/Button.js';
27 import Modal from 'react-bootstrap/lib/Modal.js';
28 import GlobalAutoCompleteSearchBar from 'app/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBar.jsx';
29 import {postAnalyticsData, getStoreAnalyticsPayload} from 'app/analytics/AnalyticsActions.js';
30 import GlobalInlineMessageBar from 'app/globalInlineMessageBar/GlobalInlineMessageBar.jsx';
31 import {getClearGlobalMessageEvent} from 'app/globalInlineMessageBar/GlobalInlineMessageBarActions.js';
32 import {externalUrlRequest, externalMessageRequest, getSubscriptionPayload} from 'app/contextHandler/ContextHandlerActions.js';
33 import { getConfigurableViewConfigs } from 'app/configurableViews/ConfigurableViewActions.js';
36 } from 'utils/GlobalConstants.js';
41 } from 'react-router-dom';
46 MENU_ITEM_TIER_SUPPORT,
48 } from './MainScreenWrapperConstants.js';
52 clearExtensibleViewData,
54 } from './MainScreenWrapperActionHelper.js';
56 import {clearSuggestionsTextField} from 'app/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBarActions.js';
57 import {changeUrlAddress} from 'utils/Routes.js';
58 import extensibleViews from 'resources/views/extensibleViews.json';
59 import {getPersonalizationDetails} from 'app/personlaization/PersonalizationActions.js';
60 import {isEmpty} from 'lodash';
62 const mapStateToProps = ({mainWrapper, configurableViews}) => {
65 toggleButtonActive = false,
66 externalRequestFound = {},
68 subscriptionPayload = {},
69 subscriptionEnabled = false,
70 aaiTopLeftPersonalizedHeader = AAI_TOP_LEFT_HEADER,
71 aaiPersonalizedHtmlDocumentTitle = AAI_HTML_TITLE
75 configurableViewsConfig
76 } = configurableViews;
85 configurableViewsConfig,
86 aaiTopLeftPersonalizedHeader,
87 aaiPersonalizedHtmlDocumentTitle
92 const mapActionsToProps = (dispatch) => {
94 onShowMenu: () => dispatch(showMainMenu(true)),
96 dispatch(showMainMenu(false));
98 dispatchAnalyticsData: () => dispatch(
99 postAnalyticsData(getStoreAnalyticsPayload())),
100 onRouteChange: () => {
101 dispatch(getClearGlobalMessageEvent());
102 dispatch(clearSuggestionsTextField());
103 dispatch(clearExtensibleViewData());
104 dispatch(clearFilters(filterBarActionTypes.CLEAR_FILTERS));
105 dispatch(setSecondaryTitle(undefined));
107 onExternalUrlRequest: (urlParamString) => {
108 dispatch(externalUrlRequest(urlParamString));
110 onExternalMessageRecieved: (messageJson) => {
111 dispatch(externalMessageRequest(messageJson));
113 onGetSubscriptionPayload: () => {
114 dispatch(getSubscriptionPayload());
116 onFetchCustomViews: () => {
117 dispatch(getConfigurableViewConfigs());
119 onGetPersonalizationValues: () => {
120 dispatch(getPersonalizationDetails());
125 class MainScreenHeader extends Component {
127 showMenu: PropTypes.bool,
128 toggleButtonActive: PropTypes.bool,
129 externalRequestFound: PropTypes.object,
130 secondaryTitle: PropTypes.string,
131 subscriptionPayload: PropTypes.object,
132 aaiTopLeftPersonalizedHeader: PropTypes.string,
133 aaiPersonalizedHtmlDocumentTitle: PropTypes.string
136 navigationLinkAndCurrentPathMatch(location, to) {
137 let linkPathElements = to.split('/');
138 let locationElements = location.pathname.split('/');
140 // the element arrays above will have the route at index 1 ... need to
141 // verify if the routes match
142 return locationElements[1] === linkPathElements[1];
145 hasRouteChanged(currentPath, nextPath) {
146 let currentPathParts = currentPath.split('/');
147 let nextPathParts = nextPath.split('/');
149 if (currentPathParts[1] !== nextPathParts[1]) {
156 isValidExternalURL(url) {
157 if(decodeURIComponent(url).indexOf('&') > 0 ) {
164 componentWillMount() {
165 this.props.onGetPersonalizationValues();
166 this.props.onGetSubscriptionPayload();
167 if(this.props.match.params.externalUrl !== undefined &&
168 this.isValidExternalURL(this.props.match.params.externalUrl)) {
169 this.props.onExternalUrlRequest(this.props.match.params.externalUrl);
173 componentWillReceiveProps(nextProps) {
174 if(!isEmpty(nextProps.aaiPersonalizedHtmlDocumentTitle)) {
175 if(!sessionStorage.getItem('PAGE_TITLE') || sessionStorage.getItem('PAGE_TITLE') !== nextProps.aaiPersonalizedHtmlDocumentTitle) {
176 sessionStorage.setItem('PAGE_TITLE', nextProps.aaiPersonalizedHtmlDocumentTitle);
178 document.title = nextProps.aaiPersonalizedHtmlDocumentTitle;
180 document.title = AAI_HTML_TITLE;
182 if (this.props.location &&
183 this.props.location.pathname !==
184 nextProps.location.pathname) {
186 this.props.dispatchAnalyticsData();
188 if (this.hasRouteChanged(this.props.location.pathname,
189 nextProps.location.pathname)) {
190 this.props.onRouteChange();
194 if(nextProps.match.params.externalUrl !== undefined &&
195 nextProps.match.params.externalUrl !== this.props.match.params.externalUrl &&
196 this.isValidExternalURL(nextProps.match.params.externalUrl)) {
197 this.props.onExternalUrlRequest(nextProps.match.params.externalUrl);
199 /* if the externalURL is not valid, we do not add any message as other proper
200 views will get that messages since the route will be this parameter.*/
202 if(this.props.externalRequestFound !== nextProps.externalRequestFound &&
203 nextProps.externalRequestFound !== undefined && nextProps.externalRequestFound.suggestion !== undefined) {
204 changeUrlAddress(nextProps.externalRequestFound.suggestion, nextProps.history);
207 if (nextProps.subscriptionEnabled) {
208 if (nextProps.subscriptionPayload !== this.props.subscriptionPayload &&
209 Object.keys(nextProps.subscriptionPayload).length > 0) {
210 var getWindowUrl = function (url) {
211 var split = url.split('/');
212 return split[0] + '//' + split[2];
214 window.parent.postMessage(
215 JSON.stringify(nextProps.subscriptionPayload),
216 getWindowUrl(document.referrer));
221 receiveMessage(event, $this) {
222 function isJson(str) {
230 if(isJson(event.data)) {
231 let messageData = JSON.parse(event.data);
232 if(isJson(messageData.message)) {
233 $this.props.onExternalMessageRecieved(messageData.message);
238 componentDidMount() {
239 //TODO Move this logic to the component will receive props.
240 //Check if the event lister is available and if the subscription is
241 // enabled before registering for it
242 if(document.referrer) {
244 window.addEventListener('message', function (e) {
245 $this.receiveMessage(e, $this);
249 // fetch custom views
250 this.props.onFetchCustomViews();
253 componentWillUnmount() {
254 if(this.props.subscriptionEnabled) {
256 window.removeEventListener('message', function (e) {
257 $this.receiveMessage(e, $this);
269 configurableViewsConfig,
270 aaiTopLeftPersonalizedHeader
273 let menuOptions = [];
275 const MenuItem = ({label, iconClass, to}) => (
276 <Route path={to} children={({location}) => (
277 <NavLink to={to} onClick={onHideMenu}>
278 <div className={this.navigationLinkAndCurrentPathMatch(location, to) ? 'main-menu-button-active' : 'main-menu-button'}>
279 <div className={iconClass}/>
280 <div className='button-icon'>{label}</div>
286 const ConfigurableMenuItem = ({label, to}) => (
287 <Route path={to} children={({location}) => (
288 <NavLink to={to} onClick={onHideMenu}>
289 <div className={this.navigationLinkAndCurrentPathMatch(location, to) ?
290 'main-menu-button-active' : 'main-menu-button'}>
291 <div className='button-icon configurable-view-button-icon'/>
292 <div className='button-icon'>{label}</div>
298 // add Tier Support view
300 <MenuItem key='schemaMenu' to='/schema' label={MENU_ITEM_TIER_SUPPORT}
301 iconClass='button-icon view-inspect-button-icon'/>
306 <MenuItem key='vnfSearchMenu'
308 label={MENU_ITEM_VNF_SEARCH}
309 iconClass='button-icon vnf-search-button-icon'/>
312 // add all custom view menu options
313 for (let view in extensibleViews) {
314 let shouldDisplayIcon = false;
315 if(extensibleViews[view]['onlyRoute'] === undefined){
316 shouldDisplayIcon = true;
317 } else if(extensibleViews[view]['onlyRoute'] === false){
318 shouldDisplayIcon = true;
320 if(shouldDisplayIcon === true){
322 <MenuItem key={extensibleViews[view]['viewName'] + 'Menu'} to={'/' + extensibleViews[view]['viewName']}
323 label={extensibleViews[view]['displayName']}
324 iconClass={'button-icon ' + extensibleViews[view]['iconClass']}/>
329 if (configurableViewsConfig && configurableViewsConfig.layouts) {
330 for (let configurableView in configurableViewsConfig.layouts) {
332 <ConfigurableMenuItem key={configurableViewsConfig.layouts[configurableView]['id'] + 'Menu'} to={'/' + configurableViewsConfig.layouts[configurableView]['id']}
333 label={configurableViewsConfig.layouts[configurableView]['title']}/>
338 let secondaryTitleClass = 'secondary-header';
339 if (secondaryTitle === undefined || secondaryTitle === '') {
340 secondaryTitleClass = secondaryTitleClass + ' hidden';
344 <div className='header'>
347 bsClass={(toggleButtonActive)
348 ? 'toggle-view-button-active'
349 : 'toggle-view-button'}
350 onClick={onShowMenu}>
351 <FontAwesome name='bars'/>
353 <Modal show={showMenu} onHide={onHideMenu}
354 dialogClassName='modal-main-menu'>
359 <span className='application-title'>{aaiTopLeftPersonalizedHeader}</span>
360 <GlobalAutoCompleteSearchBar history={this.props.history}/>
362 <GlobalInlineMessageBar />
363 <div className={secondaryTitleClass}>
364 <span className='secondary-title'>{secondaryTitle}</span>
371 export default connect(mapStateToProps, mapActionsToProps)(MainScreenHeader);