Skip to content

Commit 7157c2e

Browse files
committed
Additional fixes of responsiveness
a
1 parent 2bb4135 commit 7157c2e

File tree

4 files changed

+161
-114
lines changed

4 files changed

+161
-114
lines changed

src/shared/components/Carousel.jsx

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* A standard carousel component.
3+
*
4+
* Currently this is a wrapper arround nuka-carousel, that improves its
5+
* responsiveness to the viewport size changes:
6+
* - Shows / hides scrolling buttons when necessary;
7+
* - Aligns the content in center when all cards can be shown at once.
8+
*/
9+
10+
/* global window */
11+
12+
import Nuka from 'nuka-carousel';
13+
import PT from 'prop-types';
14+
import React from 'react';
15+
16+
/* We have to use state component, as we need to manipulate with DOM nodes to
17+
* access nuka-carousel state. */
18+
export default class Carousel extends React.Component {
19+
constructor(props) {
20+
super(props);
21+
this.check = this.check.bind(this);
22+
this.state = {};
23+
}
24+
25+
componentDidMount() {
26+
window.addEventListener('resize', this.check);
27+
}
28+
29+
componentWillUnmount() {
30+
window.removeEventListener('resize', this.check);
31+
}
32+
33+
/**
34+
* Checks carousel state to determine, whether the left / right arrows should
35+
* be shown.
36+
*/
37+
check() {
38+
if (!this.carousel) return;
39+
const st = this.carousel.state;
40+
const showNext = st.currentSlide < st.slideCount - st.slidesToScroll;
41+
const showPrev = st.left < 0;
42+
if (showNext !== this.state.showNext
43+
|| showPrev !== this.state.showPrev) {
44+
this.setState({ showPrev, showNext });
45+
}
46+
}
47+
48+
render() {
49+
const { children, NextButton, PrevButton } = this.props;
50+
const st = this.state;
51+
const decorators = [];
52+
if (st.showNext && NextButton) {
53+
decorators.push({
54+
component: () => (
55+
<NextButton
56+
onClick={() => this.carousel && this.carousel.nextSlide()}
57+
/>
58+
),
59+
position: 'CenterRight',
60+
style: {
61+
cursor: 'pointer',
62+
marginRight: 40,
63+
},
64+
});
65+
}
66+
if (st.showPrev && PrevButton) {
67+
decorators.push({
68+
component: () => (
69+
<PrevButton
70+
onClick={() => this.carousel && this.carousel.previousSlide()}
71+
/>
72+
),
73+
position: 'CenterLeft',
74+
style: {
75+
cursor: 'pointer',
76+
marginLeft: 40,
77+
},
78+
});
79+
}
80+
return (
81+
<Nuka
82+
{...this.props}
83+
afterSlide={() => setImmediate(() => this.check())}
84+
decorators={decorators}
85+
framePadding="0 100px"
86+
ref={(node) => {
87+
this.carousel = node;
88+
if (node) this.check();
89+
}}
90+
slidesToScroll="auto"
91+
style={{
92+
display: 'flex',
93+
justifyContent: 'center',
94+
}}
95+
>{children}</Nuka>
96+
);
97+
}
98+
}
99+
100+
Carousel.defaultProps = {
101+
NextButton: null,
102+
PrevButton: null,
103+
};
104+
105+
Carousel.propTypes = {
106+
children: PT.node.isRequired,
107+
NextButton: PT.func,
108+
PrevButton: PT.func,
109+
};

src/shared/components/Dashboard/MemberMetrics/Earnings/Dial/style.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
margin: 0 auto;
77
padding: 20px 30px;
88
text-align: center;
9+
width: 300px;
910
}
1011

1112
.content {

src/shared/components/Dashboard/MemberMetrics/Earnings/index.jsx

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import _ from 'lodash';
2+
import Carousel from 'components/Carousel';
23
import config from 'utils/config';
34
import PT from 'prop-types';
45
import React from 'react';
56

67
import { Link } from 'topcoder-react-utils';
78

89
import Dial from './Dial';
10+
import LArrow from '../../../../../assets/images/arrow-prev.svg';
11+
import RArrow from '../../../../../assets/images/arrow-next.svg';
912

1013
import './style.scss';
1114

@@ -37,24 +40,30 @@ export default function Earnings({ finances, showEarnings }) {
3740
if (owed && paid) {
3841
return (
3942
<div styleName="container">
40-
<Dial
41-
amount={paid}
42-
show={showEarnings}
43-
title="Paid"
44-
url={PACTS_FULL_URL}
45-
/>
46-
<Dial
47-
amount={owed}
48-
show={showEarnings}
49-
title="Owed"
50-
url={PACTS_OWED_URL}
51-
/>
52-
<Dial
53-
amount={total}
54-
show={showEarnings}
55-
title="Total"
56-
url={PACTS_FULL_URL}
57-
/>
43+
<Carousel
44+
NextButton={RArrow}
45+
PrevButton={LArrow}
46+
slideWidth="300px"
47+
>
48+
<Dial
49+
amount={paid}
50+
show={showEarnings}
51+
title="Paid"
52+
url={PACTS_FULL_URL}
53+
/>
54+
<Dial
55+
amount={owed}
56+
show={showEarnings}
57+
title="Owed"
58+
url={PACTS_OWED_URL}
59+
/>
60+
<Dial
61+
amount={total}
62+
show={showEarnings}
63+
title="Total"
64+
url={PACTS_FULL_URL}
65+
/>
66+
</Carousel>
5867
</div>
5968
);
6069
}

src/shared/components/Dashboard/MemberMetrics/Records/index.jsx

Lines changed: 24 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import _ from 'lodash';
2-
import Carousel from 'nuka-carousel';
2+
import Carousel from 'components/Carousel';
33
import PT from 'prop-types';
44
import React from 'react';
55

@@ -9,8 +9,6 @@ import RArrow from '../../../../../assets/images/arrow-next.svg';
99

1010
import './style.scss';
1111

12-
/* global window */
13-
1412
/**
1513
* Transforms stats object to a more convenient array representation.
1614
* @param {Object} stats
@@ -63,99 +61,29 @@ function transformStats(stats) {
6361
return res;
6462
}
6563

66-
export default class Records extends React.Component {
67-
constructor(props) {
68-
super(props);
69-
this.state = {};
70-
this.check = this.check.bind(this);
71-
this.width = 0;
72-
}
73-
74-
componentDidMount() {
75-
window.addEventListener('resize', this.check);
76-
}
77-
78-
componentWillUnmount() {
79-
window.removeEventListener('resize', this.check);
80-
}
81-
82-
check() {
83-
if (!this.carousel) return;
84-
const st = this.carousel.state;
85-
const showLeft = st.left < 0;
86-
const showRight = st.currentSlide < st.slideCount - st.slidesToScroll;
87-
if (showLeft === this.state.showLeft
88-
&& showRight === this.state.showRight) return;
89-
this.setState({ showLeft, showRight });
90-
}
91-
92-
render() {
93-
const st = this.state;
94-
const { stats } = this.props;
95-
96-
const decorators = [];
97-
if (st.showLeft) {
98-
decorators.push({
99-
component: () => (
100-
<LArrow
101-
onClick={() => this.carousel && this.carousel.previousSlide()}
102-
/>
103-
),
104-
position: 'CenterLeft',
105-
style: {
106-
cursor: 'pointer',
107-
marginLeft: 40,
108-
},
109-
});
110-
}
111-
if (st.showRight) {
112-
decorators.push({
113-
component: () => (
114-
<RArrow
115-
onClick={() => this.carousel && this.carousel.nextSlide()}
116-
/>
117-
),
118-
position: 'CenterRight',
119-
style: {
120-
cursor: 'pointer',
121-
marginRight: 40,
122-
},
123-
});
124-
}
125-
126-
return (
127-
<div>
128-
<Carousel
129-
afterSlide={() => setImmediate(() => this.check())}
130-
decorators={decorators}
131-
framePadding="0 100px"
132-
ref={(node) => {
133-
this.carousel = node;
134-
if (node) this.check();
135-
}}
136-
slidesToScroll="auto"
137-
slideWidth="200px"
138-
style={{
139-
display: 'flex',
140-
justifyContent: 'center',
141-
}}
142-
>
143-
{
144-
transformStats(stats).map(item => (
145-
<Dial
146-
key={`${item.track}-${item.subTrack}`}
147-
handle={stats.handle}
148-
track={item.track}
149-
subTrack={item.subTrack}
150-
metric={item.metric}
151-
value={item.value}
152-
/>
153-
))
154-
}
155-
</Carousel>
156-
</div>
157-
);
158-
}
64+
export default function Records({ stats }) {
65+
return (
66+
<div>
67+
<Carousel
68+
NextButton={RArrow}
69+
PrevButton={LArrow}
70+
slideWidth="200px"
71+
>
72+
{
73+
transformStats(stats).map(item => (
74+
<Dial
75+
key={`${item.track}-${item.subTrack}`}
76+
handle={stats.handle}
77+
track={item.track}
78+
subTrack={item.subTrack}
79+
metric={item.metric}
80+
value={item.value}
81+
/>
82+
))
83+
}
84+
</Carousel>
85+
</div>
86+
);
15987
}
16088

16189
Records.propTypes = {

0 commit comments

Comments
 (0)