Skip to content

Commit 58fcc1e

Browse files
authored
Merge pull request #4631 from ric0de/WV-2289TrackingSubtabs
[WV-2289] ManageMyCandidates "Tracking" subtabs [TEAM REVIEW]
2 parents 330bedd + e83854a commit 58fcc1e

File tree

4 files changed

+231
-10
lines changed

4 files changed

+231
-10
lines changed
Lines changed: 150 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,159 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import styled from 'styled-components';
3+
import { Search as SearchIcon } from '@mui/icons-material';
34
import DesignTokenColors from '../../common/components/Style/DesignTokenColors';
45

6+
import SupportersJoined from './SupportersJoined';
7+
import SupportersInvited from './SupportersInvited';
8+
import SupportersToRemind from './SupportersToRemind';
9+
510
export default function SupporterTracking () {
11+
const [activeTab, setActiveTab] = useState('joined');
12+
13+
// TO DO: Replace these placeholders with actual logic
14+
const joinedCount = 3;
15+
const invitedCount = 3;
16+
const remindCount = 1;
17+
18+
const renderTabContent = () => {
19+
switch (activeTab) {
20+
case 'joined':
21+
return <SupportersJoined />;
22+
case 'invited':
23+
return <SupportersInvited />;
24+
case 'remind':
25+
return <SupportersToRemind />;
26+
default:
27+
return <SupportersJoined />;
28+
}
29+
};
30+
631
return (
7-
<Placeholder>
8-
Tracking (coming soon)
9-
</Placeholder>
32+
<>
33+
<HeaderRow>
34+
<H2>Tracking</H2>
35+
<HeaderDivider />
36+
<SearchIconButton
37+
type="button"
38+
aria-label="Search"
39+
onClick={() => console.log('TODO: implement search feature')}
40+
>
41+
<SearchIcon fontSize="medium" />
42+
</SearchIconButton>
43+
</HeaderRow>
44+
<TrackingText>Follow up on your invitees and those who joined.</TrackingText>
45+
<TabRow>
46+
<Tab
47+
active={activeTab === 'joined'}
48+
onClick={() => setActiveTab('joined')}
49+
data-hidden-bold-text={`Joined WeVote (${joinedCount})`}
50+
>
51+
Joined WeVote ({joinedCount})
52+
</Tab>
53+
<Tab
54+
active={activeTab === 'invited'}
55+
onClick={() => setActiveTab('invited')}
56+
data-hidden-bold-text={`Invited (${invitedCount})`}
57+
>
58+
Invited ({invitedCount})
59+
</Tab>
60+
<Tab
61+
active={activeTab === 'remind'}
62+
onClick={() => setActiveTab('remind')}
63+
data-hidden-bold-text={`Reminder needed (${remindCount})`}
64+
>
65+
Reminder needed ({remindCount})
66+
</Tab>
67+
</TabRow>
68+
<TabContent>
69+
{renderTabContent()}
70+
</TabContent>
71+
</>
1072
);
1173
}
1274

13-
const Placeholder = styled.div`
14-
background: ${DesignTokenColors.neutralUI50};
15-
border: 1px dashed ${DesignTokenColors.neutralUI300};
16-
border-radius: 12px;
17-
color: ${DesignTokenColors.neutralUI600};
18-
padding: 24px;
75+
// Styles
76+
77+
const H2 = styled.h2`
78+
color: ${DesignTokenColors.neutralUI900};
79+
font-size: 20px;
80+
font-weight: 400;
81+
margin: 0;
82+
`;
83+
84+
const HeaderDivider = styled.span`
85+
border-left: 1.5px solid ${DesignTokenColors.neutralUI100};
86+
height: 30px;
87+
margin: 0 4px 0 12px;
88+
`;
89+
90+
const HeaderRow = styled.div`
91+
align-items: center;
92+
display: flex;
93+
gap: 2px;
94+
margin: -6px 0 8px;
95+
`;
96+
97+
const SearchIconButton = styled.button`
98+
align-items: center;
99+
background: none;
100+
border: none;
101+
border-radius: 8px;
102+
color: ${DesignTokenColors.neutralUI700};
103+
cursor: pointer;
104+
display: inline-flex;
105+
padding: 6px;
106+
&:hover {
107+
background: ${DesignTokenColors.neutralUI50};
108+
color: ${DesignTokenColors.neutralUI900};
109+
}
110+
`;
111+
112+
const Tab = styled.button`
113+
background: none;
114+
border: none;
115+
padding: 12px 16px 4px 16px;
116+
font-size: 15px;
117+
font-weight: ${props => props.active ? '600' : '500'};
118+
color: ${props => props.active ? DesignTokenColors.primary600 : DesignTokenColors.neutralUI700};
119+
border-bottom: 2px solid ${props => props.active ? DesignTokenColors.primary600 : 'transparent'};
120+
cursor: pointer;
121+
position: relative;
122+
bottom: -1px;
123+
124+
// We use data-hidden-bold-text to render an invisible bolded duplicate of the tab's text
125+
// so there's no awkward shiftiness in the layout when switching between tabs.
126+
// It's hidden visually, un-interactable, and hidden from screen readers.
127+
&::after {
128+
content: attr(data-hidden-bold-text);
129+
height: 0;
130+
visibility: hidden;
131+
overflow: hidden;
132+
user-select: none;
133+
pointer-events: none;
134+
font-weight: 600;
135+
display: block;
136+
@media speech {
137+
display: none;
138+
}
139+
}
140+
&:hover {
141+
color: ${DesignTokenColors.primary600};
142+
}
143+
`;
144+
145+
const TabContent = styled.div`
146+
flex: 1;
147+
`;
148+
149+
const TabRow = styled.div`
150+
display: flex;
151+
gap: 0;
152+
border-bottom: 1px solid ${DesignTokenColors.neutralUI200};
153+
margin-bottom: 24px;
154+
`;
155+
156+
const TrackingText = styled.p`
157+
color: ${DesignTokenColors.neutralUI700};
158+
margin: 0 0 6px;
19159
`;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
import DesignTokenColors from '../../common/components/Style/DesignTokenColors';
4+
5+
export default function SupportersInvited () {
6+
return (
7+
<Container>
8+
<Placeholder>
9+
Invited supporters will go here
10+
</Placeholder>
11+
</Container>
12+
);
13+
}
14+
15+
const Container = styled.div`
16+
display: flex;
17+
flex-direction: column;
18+
`;
19+
20+
const Placeholder = styled.div`
21+
background: ${DesignTokenColors.neutralUI50};
22+
border: 1px dashed ${DesignTokenColors.neutralUI300};
23+
border-radius: 12px;
24+
color: ${DesignTokenColors.neutralUI600};
25+
padding: 24px;
26+
text-align: center;
27+
`;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
import DesignTokenColors from '../../common/components/Style/DesignTokenColors';
4+
5+
export default function SupportersJoined () {
6+
return (
7+
<Container>
8+
<Placeholder>
9+
Supporters who joined WeVote will go here
10+
</Placeholder>
11+
</Container>
12+
);
13+
}
14+
15+
const Container = styled.div`
16+
display: flex;
17+
flex-direction: column;
18+
`;
19+
20+
const Placeholder = styled.div`
21+
background: ${DesignTokenColors.neutralUI50};
22+
border: 1px dashed ${DesignTokenColors.neutralUI300};
23+
border-radius: 12px;
24+
color: ${DesignTokenColors.neutralUI600};
25+
padding: 24px;
26+
text-align: center;
27+
`;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
import DesignTokenColors from '../../common/components/Style/DesignTokenColors';
4+
5+
export default function SupportersToRemind () {
6+
return (
7+
<Container>
8+
<Placeholder>
9+
Supporters who need reminders will go here
10+
</Placeholder>
11+
</Container>
12+
);
13+
}
14+
15+
const Container = styled.div`
16+
display: flex;
17+
flex-direction: column;
18+
`;
19+
20+
const Placeholder = styled.div`
21+
background: ${DesignTokenColors.neutralUI50};
22+
border: 1px dashed ${DesignTokenColors.neutralUI300};
23+
border-radius: 12px;
24+
color: ${DesignTokenColors.neutralUI600};
25+
padding: 24px;
26+
text-align: center;
27+
`;

0 commit comments

Comments
 (0)