@@ -5,11 +5,17 @@ import { AppContext } from '@edx/frontend-platform/react';
5
5
import {
6
6
APP_CONFIG_INITIALIZED ,
7
7
ensureConfig ,
8
+ getConfig ,
8
9
mergeConfig ,
9
10
subscribe ,
10
11
} from '@edx/frontend-platform' ;
12
+ import { ActionRow } from '@edx/paragon' ;
11
13
12
- import DesktopHeader from './DesktopHeader' ;
14
+ import { Menu , MenuTrigger , MenuContent } from './Menu' ;
15
+ import Avatar from './Avatar' ;
16
+ import { LinkedLogo , Logo } from './Logo' ;
17
+
18
+ import { CaretIcon } from './Icons' ;
13
19
14
20
import messages from './Header.messages' ;
15
21
@@ -28,7 +34,124 @@ subscribe(APP_CONFIG_INITIALIZED, () => {
28
34
} , 'StudioHeader additional config' ) ;
29
35
} ) ;
30
36
31
- function StudioHeader ( { intl, mainMenu, appMenu } ) {
37
+ class StudioDesktopHeaderBase extends React . Component {
38
+ constructor ( props ) { // eslint-disable-line no-useless-constructor
39
+ super ( props ) ;
40
+ }
41
+
42
+ renderUserMenu ( ) {
43
+ const {
44
+ userMenu,
45
+ avatar,
46
+ username,
47
+ intl,
48
+ } = this . props ;
49
+
50
+ return (
51
+ < Menu transitionClassName = "menu-dropdown" transitionTimeout = { 250 } >
52
+ < MenuTrigger
53
+ tag = "button"
54
+ aria-label = { intl . formatMessage ( messages [ 'header.label.account.menu.for' ] , { username } ) }
55
+ className = "btn btn-outline-primary d-inline-flex align-items-center pl-2 pr-3"
56
+ >
57
+ < Avatar size = "1.5em" src = { avatar } alt = "" className = "mr-2" />
58
+ { username } < CaretIcon role = "img" aria-hidden focusable = "false" />
59
+ </ MenuTrigger >
60
+ < MenuContent className = "mb-0 dropdown-menu show dropdown-menu-right pin-right shadow py-2" >
61
+ { userMenu . map ( ( { type, href, content } ) => (
62
+ < a className = { `dropdown-${ type } ` } key = { `${ type } -${ content } ` } href = { href } > { content } </ a >
63
+ ) ) }
64
+ </ MenuContent >
65
+ </ Menu >
66
+ ) ;
67
+ }
68
+
69
+ renderLoggedOutItems ( ) {
70
+ const { loggedOutItems } = this . props ;
71
+
72
+ return loggedOutItems . map ( ( item , i , arr ) => (
73
+ < a
74
+ key = { `${ item . type } -${ item . content } ` }
75
+ className = { i < arr . length - 1 ? 'btn mr-2 btn-link' : 'btn mr-2 btn-outline-primary' }
76
+ href = { item . href }
77
+ >
78
+ { item . content }
79
+ </ a >
80
+ ) ) ;
81
+ }
82
+
83
+ render ( ) {
84
+ const {
85
+ logo,
86
+ logoAltText,
87
+ logoDestination,
88
+ loggedIn,
89
+ intl,
90
+ actionRowContent,
91
+ } = this . props ;
92
+ const logoProps = { src : logo , alt : logoAltText , href : logoDestination } ;
93
+ const logoClasses = getConfig ( ) . AUTHN_MINIMAL_HEADER ? 'mw-100' : null ;
94
+
95
+ return (
96
+ < header className = "site-header-desktop" >
97
+ < a className = "nav-skip sr-only sr-only-focusable" href = "#main" > { intl . formatMessage ( messages [ 'header.label.skip.nav' ] ) } </ a >
98
+ < div className = { `container-fluid ${ logoClasses } ` } >
99
+ < div className = "nav-container position-relative d-flex align-items-center" >
100
+ { logoDestination === null ? < Logo className = "logo" src = { logo } alt = { logoAltText } /> : < LinkedLogo className = "logo" { ...logoProps } /> }
101
+ < ActionRow >
102
+ { actionRowContent }
103
+ < nav
104
+ aria-label = { intl . formatMessage ( messages [ 'header.label.secondary.nav' ] ) }
105
+ className = "nav secondary-menu-container align-items-center ml-auto"
106
+ >
107
+ { loggedIn ? this . renderUserMenu ( ) : this . renderLoggedOutItems ( ) }
108
+ </ nav >
109
+ </ ActionRow >
110
+ </ div >
111
+ </ div >
112
+ </ header >
113
+ ) ;
114
+ }
115
+ }
116
+
117
+ StudioDesktopHeaderBase . propTypes = {
118
+ userMenu : PropTypes . arrayOf ( PropTypes . shape ( {
119
+ type : PropTypes . oneOf ( [ 'item' , 'menu' ] ) ,
120
+ href : PropTypes . string ,
121
+ content : PropTypes . string ,
122
+ } ) ) ,
123
+ loggedOutItems : PropTypes . arrayOf ( PropTypes . shape ( {
124
+ type : PropTypes . oneOf ( [ 'item' , 'menu' ] ) ,
125
+ href : PropTypes . string ,
126
+ content : PropTypes . string ,
127
+ } ) ) ,
128
+ logo : PropTypes . string ,
129
+ logoAltText : PropTypes . string ,
130
+ logoDestination : PropTypes . string ,
131
+ avatar : PropTypes . string ,
132
+ username : PropTypes . string ,
133
+ loggedIn : PropTypes . bool ,
134
+ actionRowContent : PropTypes . element ,
135
+
136
+ // i18n
137
+ intl : intlShape . isRequired ,
138
+ } ;
139
+
140
+ StudioDesktopHeaderBase . defaultProps = {
141
+ userMenu : [ ] ,
142
+ loggedOutItems : [ ] ,
143
+ logo : null ,
144
+ logoAltText : null ,
145
+ logoDestination : null ,
146
+ avatar : null ,
147
+ username : null ,
148
+ loggedIn : false ,
149
+ actionRowContent : null ,
150
+ } ;
151
+
152
+ const StudioDesktopHeader = injectIntl ( StudioDesktopHeaderBase ) ;
153
+
154
+ function StudioHeader ( { intl, actionRowContent } ) {
32
155
const { authenticatedUser, config } = useContext ( AppContext ) ;
33
156
34
157
const userMenu = authenticatedUser === null ? [ ] : [
@@ -56,44 +179,21 @@ function StudioHeader({ intl, mainMenu, appMenu }) {
56
179
loggedIn : authenticatedUser !== null ,
57
180
username : authenticatedUser !== null ? authenticatedUser . username : null ,
58
181
avatar : authenticatedUser !== null ? authenticatedUser . avatar : null ,
59
- mainMenu ,
182
+ actionRowContent ,
60
183
userMenu,
61
- appMenu,
62
184
loggedOutItems : [ ] ,
63
185
} ;
64
186
65
- return < DesktopHeader { ...props } /> ;
187
+ return < StudioDesktopHeader { ...props } /> ;
66
188
}
67
189
68
190
StudioHeader . propTypes = {
69
191
intl : intlShape . isRequired ,
70
- appMenu : PropTypes . shape (
71
- {
72
- content : PropTypes . string ,
73
- href : PropTypes . string ,
74
- menuItems : PropTypes . arrayOf (
75
- PropTypes . shape ( {
76
- type : PropTypes . string ,
77
- href : PropTypes . string ,
78
- content : PropTypes . string ,
79
- } ) ,
80
- ) ,
81
- } ,
82
- ) ,
83
- mainMenu : PropTypes . arrayOf (
84
- PropTypes . shape (
85
- {
86
- type : PropTypes . string ,
87
- href : PropTypes . string ,
88
- content : PropTypes . string ,
89
- } ,
90
- ) ,
91
- ) ,
192
+ actionRowContent : PropTypes . element ,
92
193
} ;
93
194
94
195
StudioHeader . defaultProps = {
95
- appMenu : null ,
96
- mainMenu : [ ] ,
196
+ actionRowContent : < > </ > ,
97
197
} ;
98
198
99
199
export default injectIntl ( StudioHeader ) ;
0 commit comments