-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAppHeader.jsx
140 lines (126 loc) · 5.15 KB
/
AppHeader.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import PropTypes from 'prop-types';
import { usePropsSelector, useT, useUid, useHandlers } from '../hooks';
import { compose, identity } from '../utils/fn.js';
import { actions } from '../reducers';
import { detectBrowserLocale, fetchMissingMessages } from '../lang.js';
import { classes } from '../utils/string.js';
export const defaultOnDropdownMenuKeyUp = e => {
const maybeFocusItem = el => el && el.querySelector('.dropdown-item').focus();
const li = e.target.closest('li');
if (e.key === 'ArrowUp') maybeFocusItem(li.previousElementSibling);
else if (e.key === 'ArrowDown') maybeFocusItem(li.nextElementSibling);
};
export const getDispName = Component => Component.displayName || Component.name;
export const ApplyToProps = (fn, Component, name) => {
const WrappedComponent = props => Component(fn(props));
WrappedComponent.displayName = `ApplyToProps(${name || getDispName(Component)})`;
return WrappedComponent;
};
export const HeaderMenu = ApplyToProps(compose(
useUid,
useHandlers({ onDropdownMenuKeyUp: defaultOnDropdownMenuKeyUp })
), ({
$uid,
className,
items,
selectedItem,
hoverText,
onDropdownMenuKeyUp,
onDropdownMenuClick,
itemIdFn = identity,
renderItem = identity
}) => {
const unselectedItems = items.filter(p => itemIdFn(p) !== itemIdFn(selectedItem));
const menuId = `header-menu-${$uid}`;
const buttonClasses = classes => `${classes} btn py-3 px-4 text-white`;
return (
<div className={classes(className, 'header-menu dropdown d-inline-block')} title={hoverText}>
<button className={buttonClasses('dropdown-toggle')} type="button" id={menuId} data-id={itemIdFn(selectedItem)}>
{renderItem(selectedItem)}
</button>
<ul className="dropdown-menu dropdown-menu-dark py-0 start-0 end-0" aria-labelledby={menuId} onKeyUp={onDropdownMenuKeyUp}>
{unselectedItems.map(item => (
<li key={itemIdFn(item)}>
<button className={buttonClasses('dropdown-item')} type="button" onClick={onDropdownMenuClick} data-id={itemIdFn(item)}>
{renderItem(item)}
</button>
</li>
))}
</ul>
</div>
);
}, 'HeaderMenu');
HeaderMenu.propTypes = {
$uid: PropTypes.number,
className: PropTypes.string,
items: PropTypes.array,
selectedItem: PropTypes.any,
itemIdFn: PropTypes.func,
hoverText: PropTypes.string,
renderItem: PropTypes.func,
onDropdownMenuKeyUp: PropTypes.func,
onDropdownMenuClick: PropTypes.func
};
export const defaultOnSelectProfile = e => {
e.preventDefault();
e.$dispatch(actions.SELECT_PROFILE({
id: Number(e.currentTarget.dataset.id),
browserLocale: detectBrowserLocale()
}));
fetchMissingMessages(e.$getState, e.$dispatch);
};
export const defaultOnSelectLocale = e => {
e.preventDefault();
e.$dispatch(actions.SET_LOCALE({ locale: e.currentTarget.dataset.id }));
fetchMissingMessages(e.$getState, e.$dispatch);
};
export const AppHeader = props => {
const {
$t,
availableLocales,
selectedLocale,
onSelectLocale,
profiles,
selectedProfile,
onSelectProfile
} = compose(
useT,
usePropsSelector(s => ({
availableLocales: s.availableLocales,
selectedLocale: s.selectedProfile.locale,
profiles: s.profiles,
selectedProfile: s.selectedProfile,
})),
useHandlers({
onSelectLocale: defaultOnSelectLocale,
onSelectProfile: defaultOnSelectProfile
})
)(props);
const flagClasses = loc => `flag-icon flag-icon-${loc}`;
return (
<header className="header container-fluid mb-4">
<div className="row align-items-center">
<div className="col">
<h2 className="logotype my-2">
<a className="text-white text-decoration-none">{$t('header.heading')}</a>
</h2>
</div>
<div className="col">
<div className="float-end">
<HeaderMenu className="locale-menu" items={availableLocales} selectedItem={selectedLocale}
hoverText={$t('header.localeMenu.hoverText')} onDropdownMenuClick={onSelectLocale} renderItem={locale => (
<span className={flagClasses(locale)}></span>
)} />
<HeaderMenu className="profile-menu" items={profiles} selectedItem={selectedProfile} itemIdFn={profile => profile.id}
hoverText={$t('header.profileMenu.hoverText')} onDropdownMenuClick={onSelectProfile} renderItem={profile => (
<>
<i className="bi bi-person-circle"></i>
<em className="ms-2 fst-normal">{profile.name}</em>
</>
)} />
</div>
</div>
</div>
</header>
);
};