Skip to content
This repository was archived by the owner on Apr 5, 2022. It is now read-only.

Commit cfb8139

Browse files
CJPM-18357 add company selector
1 parent dd1b1a9 commit cfb8139

8 files changed

Lines changed: 404 additions & 0 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React from 'react';
2+
import { Demo, Snippet } from '../../../components/Demo';
3+
4+
/* s1:start */
5+
import { CompanySelector } from '@cjdev/visual-stack';
6+
/* s1:end */
7+
8+
export default () => (
9+
<Demo srcFile="/samples/src/containers/Components/Docs/company-selector.js">
10+
{snippets => (
11+
<>
12+
<Snippet tag="s1" src={snippets} />
13+
<Snippet tag="s2" src={snippets} />
14+
{/* s2:start */}
15+
<CompanySelector
16+
selectedCompany={{ name: 'Foobar', id: '111111' }}
17+
companies={[
18+
{ name: 'Foobar', id: '111111' },
19+
{ name: 'Bazbox', id: '222222' },
20+
]}
21+
/>
22+
{/* s2:end */}
23+
</>
24+
)}
25+
</Demo>
26+
);

packages/visual-stack-docs/src/containers/Components/Docs/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import ButtonDocs from './button';
1313
import ButtonWithDropdownDocs from './button-with-dropdown';
1414
import CardDocs from './card';
1515
import CollapsiblePanelDocs from './collapsiblepanel';
16+
import CompanySelector from './company-selector';
1617
import DatePickerDocs from './datepicker';
1718
import DrawerDocs from './drawer';
1819
import ExpandingInputButtonDocs from './expanding-input-button';
@@ -57,6 +58,7 @@ addComponentRoute(
5758
'Collapsible Panel',
5859
<CollapsiblePanelDocs />
5960
);
61+
addComponentRoute('companyselector', 'Company Selector', <CompanySelector />);
6062
addComponentRoute(
6163
'expanding-input-button',
6264
'Expanding Input Button',
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
@import 'material-icons.css';
2+
@import 'roboto.css';
3+
4+
:root {
5+
--cj-nav-link-color: #757575;
6+
--cj-nav-selected-page-color: #333;
7+
--cj-nav-text-color: #333;
8+
--cj-nav-text-background-color: #f6f6f6;
9+
--cj-nav-tooltip-background-color: #6d7684;
10+
--cj-green: #49c5b1;
11+
}
12+
13+
.top-nav-dropdown-container {
14+
float: right;
15+
}
16+
17+
.account-dropdown {
18+
max-width: 220px;
19+
}
20+
21+
.top-nav-dropdown {
22+
z-index: 1;
23+
background: #ffffff;
24+
width: 280px;
25+
border-radius: 3px;
26+
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.16);
27+
}
28+
29+
.company-switcher-dropdown {
30+
position: relative;
31+
top: -32px;
32+
right: 0px;
33+
}
34+
35+
.top-nav-menu-item-text {
36+
color: var(--cj-nav-text-color);
37+
}
38+
39+
.icon-menu-item {
40+
font-size: 18px;
41+
color: var(--cj-nav-link-color);
42+
transition: 0.2s all ease-in-out;
43+
}
44+
45+
.top-nav-menu-item {
46+
display: flex;
47+
align-items: center;
48+
height: 32px;
49+
}
50+
51+
.top-nav-menu-item-title {
52+
color: var(--cj-nav-text-color);
53+
font-weight: 500;
54+
}
55+
56+
.top-nav-dropdown-header {
57+
display: flex;
58+
align-items: center;
59+
justify-content: space-between;
60+
color: var(--cj-nav-text-color);
61+
height: 48px;
62+
padding: 0 16px 0 16px;
63+
font-size: 14px;
64+
font-weight: 500;
65+
}
66+
67+
.top-nav-dropdown-header .icon-dropdown {
68+
height: 32px;
69+
width: 32px;
70+
padding: 5px 5px 5px 5px;
71+
}
72+
73+
.top-nav-dropdown-container .icon-dropdown i {
74+
font-size: 18px;
75+
}
76+
77+
.icon-dropdown {
78+
font-size: 18px;
79+
color: var(--cj-nav-link-color);
80+
transition: 0.2s all ease-in-out;
81+
cursor: pointer;
82+
}
83+
84+
.icon-dropdown:hover {
85+
color: #333333;
86+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
const companySwitcherStyle = {
2+
option: (provided, state) => ({
3+
...provided,
4+
backgroundColor: null,
5+
color: state.isSelected ? '#151C23' : '#757575',
6+
fontWeight: state.isSelected ? '500' : 'normal',
7+
fontSize: '1.3rem',
8+
lineHeight: '3.2rem',
9+
padding: '0px 16px',
10+
cursor: 'pointer',
11+
'&:hover': {
12+
backgroundColor: '#F3F4F5',
13+
color: '#151C23',
14+
},
15+
}),
16+
menu: (provided, _state) => ({
17+
...provided,
18+
marginTop: '0px',
19+
borderRadius: 0,
20+
cursor: 'pointer',
21+
boxShadow: '0px 8px 16px rgba(0,0,0,.16)',
22+
borderTop: '1px solid #D6D8DC',
23+
}),
24+
control: (provided, _state) => ({
25+
...provided,
26+
borderRadius: 0,
27+
borderWidth: 0,
28+
boxShadow: 'none',
29+
borderTop: '1px solid #D6D8DC',
30+
'&:hover': {
31+
borderTop: '1px solid #D6D8DC',
32+
},
33+
}),
34+
input: provided => ({
35+
...provided,
36+
marginLeft: '48px',
37+
marginBottom: '0px',
38+
'&:focus': {
39+
boxShadow: 'none',
40+
},
41+
}),
42+
valueContainer: provided => ({
43+
...provided,
44+
height: '48px',
45+
padding: '0px',
46+
margin: '0px',
47+
}),
48+
placeholder: provided => ({
49+
...provided,
50+
marginLeft: '0px',
51+
marginRight: '0px',
52+
marginTop: '2px',
53+
}),
54+
indicatorsContainer: () => ({ display: 'none' }),
55+
};
56+
57+
export default companySwitcherStyle;
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import React, { useState } from 'react';
2+
import ReactSelect, { components } from 'react-select';
3+
4+
import companySelectorStyle from './CompanySelectorStyle';
5+
import './CompanySelector.css';
6+
7+
/**
8+
*
9+
* @param {object} selectedCompany The currently selected company
10+
* @param {string} selectedCompany.name
11+
* @param {string} selectedCompany.id The company id
12+
* @param {array} companies A list of companies of the same shape as `selectedCompany`
13+
* @returns {JSX.Element}
14+
*/
15+
export const CompanySelector = ({ selectedCompany, companies }) => {
16+
const hasMultipleCompanies = companies.length > 1;
17+
18+
const [isDropdownExpanded, setIsDropdownExpanded] = useState(false);
19+
const [company, setCompany] = useState({
20+
name: selectedCompany ? selectedCompany.name : null,
21+
id: selectedCompany ? selectedCompany.id : null,
22+
});
23+
24+
const collapseDropdown = company => {
25+
if (company) setCompany(company);
26+
setIsDropdownExpanded(false);
27+
};
28+
29+
const expandDropdown = () => setIsDropdownExpanded(true);
30+
31+
return (
32+
<div className="top-nav-dropdown-container">
33+
<MenuItem
34+
name="AccountIndicator"
35+
title={company.name}
36+
text={`(${company.id})`}
37+
dataId={'topnav-accountswitcher'}
38+
onClick={hasMultipleCompanies ? () => expandDropdown() : () => {}}
39+
showDownArrow={hasMultipleCompanies}
40+
additionalClasses={'account-dropdown'}
41+
/>
42+
{hasMultipleCompanies ? (
43+
<CompanySelectorDropdown
44+
companies={companies}
45+
selectedCompany={company.id}
46+
show={isDropdownExpanded}
47+
collapseDropdown={x => collapseDropdown(x)}
48+
/>
49+
) : (
50+
<div />
51+
)}
52+
</div>
53+
);
54+
};
55+
56+
const CompanySelectorDropdown = ({
57+
companies,
58+
selectedCompany,
59+
show,
60+
collapseDropdown,
61+
}) => {
62+
const changeCompany = (value, { action }) => {
63+
if (action === 'select-option') {
64+
const selectedCompany = value ? value.value : null;
65+
if (selectedCompany) {
66+
collapseDropdown(selectedCompany);
67+
}
68+
}
69+
};
70+
71+
const companyList = companies
72+
.map(c => ({ value: c, label: `${c.name} (${c.id})` }))
73+
.sort((a, b) => a.label.toUpperCase().localeCompare(b.label.toUpperCase()));
74+
75+
const CustomMenu = props => (
76+
<components.Menu {...props}>
77+
{props.children}
78+
<div
79+
style={{
80+
fontWeight: 'bold',
81+
textAlign: 'center',
82+
marginTop: '4px',
83+
marginBottom: '8px',
84+
display: 'none',
85+
}}
86+
>
87+
ADD LINKED ACCOUNT
88+
</div>
89+
</components.Menu>
90+
);
91+
92+
const CustomInput = props => (
93+
<components.Input {...props} autoFocus>
94+
{props.children}
95+
</components.Input>
96+
);
97+
98+
return show ? (
99+
<div className="top-nav-dropdown company-switcher-dropdown">
100+
<DropdownHeader
101+
label={'Select Account'}
102+
collapseDropdown={collapseDropdown}
103+
/>
104+
<ReactSelect
105+
components={{ Menu: CustomMenu, Input: CustomInput }}
106+
styles={companySelectorStyle}
107+
menuIsOpen={true}
108+
onChange={changeCompany}
109+
options={companyList}
110+
isOptionSelected={option => option.value === selectedCompany}
111+
placeholder={<CompanySelectorPlaceholder />}
112+
/>
113+
</div>
114+
) : (
115+
<div />
116+
);
117+
};
118+
119+
const MenuItem = ({
120+
title,
121+
text,
122+
icon,
123+
onClick,
124+
additionalClasses,
125+
dataId,
126+
showDownArrow = false,
127+
}) => {
128+
const textElement = text ? (
129+
<span className="top-nav-menu-item-text">{text}</span>
130+
) : null;
131+
const maybeDownArrow = showDownArrow ? (
132+
<span className="material-icons icon-menu-item">expand_more</span>
133+
) : null;
134+
return (
135+
<div
136+
className={`top-nav-menu-item ${additionalClasses || ''}`}
137+
onClick={onClick}
138+
data-id={dataId}
139+
>
140+
{icon}
141+
{title ? (
142+
<span className="top-nav-menu-item-title truncate">{title}&nbsp;</span>
143+
) : null}
144+
{textElement}
145+
{maybeDownArrow}
146+
</div>
147+
);
148+
};
149+
150+
const DropdownHeader = ({ label, collapseDropdown }) => (
151+
<div className="top-nav-dropdown-header">
152+
<div>{label}</div>
153+
{
154+
<div className="icon-dropdown" onClick={() => collapseDropdown()}>
155+
<i className="material-icons" alt="close">
156+
close
157+
</i>
158+
</div>
159+
}
160+
</div>
161+
);
162+
163+
const CompanySelectorPlaceholder = () => (
164+
<>
165+
<div
166+
style={{
167+
width: '48px',
168+
height: '48px',
169+
display: 'inline-block',
170+
padding: '15px',
171+
}}
172+
>
173+
<i
174+
className="material-icons icon-search"
175+
style={{ fontSize: '18px' }}
176+
alt="search icon"
177+
>
178+
search
179+
</i>{' '}
180+
</div>
181+
<div
182+
style={{
183+
fontStyle: 'italic',
184+
lineHeight: '48px',
185+
display: 'inline-block',
186+
position: 'relative',
187+
top: '-2px',
188+
}}
189+
>
190+
{'Search for accounts...'}
191+
</div>
192+
</>
193+
);

0 commit comments

Comments
 (0)