on master help sign in
include pending points in cohort list
35f56bdLiam Fitzgerald
src/views/Invite/Cohort.js+95−31
@@ -8,6 +8,7 @@ import { usePointCursor } from 'store/pointCursor';
8import { usePointCache } from 'store/pointCache';
8import { usePointCache } from 'store/pointCache';
9
9
10import View from 'components/View';
10import View from 'components/View';
11+import Tabs from 'components/Tabs';
11import BarGraph from 'components/BarGraph';
12import BarGraph from 'components/BarGraph';
12import MaybeSigil from 'components/MaybeSigil';
13import MaybeSigil from 'components/MaybeSigil';
13import { matchBlinky } from 'components/Blinky';
14import { matchBlinky } from 'components/Blinky';
@@ -23,10 +24,34 @@ import Inviter from 'views/Invite/Inviter';
23
24
24import { ReactComponent as SearchIcon } from 'assets/search.svg';
25import { ReactComponent as SearchIcon } from 'assets/search.svg';
25
26
27+function SearchInput({ className, value, onChange }) {
28+ return (
29+ <Flex align="center" full className={cn('b b-gray2 b1', className)}>
30+ <Flex.Item className="p2">
31+ <SearchIcon />
32+ </Flex.Item>
33+
34+ <Flex.Item
35+ flex={1}
36+ as={'input'}
37+ value={value}
38+ onChange={onChange}
39+ className="b-none h7"
40+ />
41+ </Flex>
42+ );
43+}
44+
26−function CohortMember({ point, className }) {
45+function CohortMember({ point, pending = false, className }) {
27 const { sentInvites } = useInvites(point);
46 const { sentInvites } = useInvites(point);
28 const patp = useMemo(() => ob.patp(point), [point]);
47 const patp = useMemo(() => ob.patp(point), [point]);
29− const colors = ['#000000', '#FFFFFF'];
48+ const colors = pending ? ['#ee892b', '#FFFFFF'] : ['#000000', '#FFFFFF'];
49+
50+ const DetailText = useCallback(
51+ () =>
52+ pending ? 'Pending' : <> {matchBlinky(sentInvites)} points invited </>,
53+ [sentInvites]
54+ );
30
55
31 return (
56 return (
32 <Flex justify="between" className={cn('b1 b-gray2', className)}>
57 <Flex justify="between" className={cn('b1 b-gray2', className)}>
@@ -41,19 +66,21 @@ function CohortMember({ point, className }) {
41 col
66 col
42 className="mono f6 ph4">
67 className="mono f6 ph4">
43 <Flex.Item>{patp}</Flex.Item>
68 <Flex.Item>{patp}</Flex.Item>
44− <Flex.Item>{matchBlinky(sentInvites)} points invited</Flex.Item>
69+ <Flex.Item className="gray4">
70+ <DetailText />
71+ </Flex.Item>
45 </Flex.Item>
72 </Flex.Item>
46 </Flex>
73 </Flex>
47 );
74 );
48}
75}
49−function CohortList({ points, className }) {
76+function CohortList({ acceptedPoints, pendingPoints, className, onlyPending }) {
50 const { syncInvites } = usePointCache();
77 const { syncInvites } = usePointCache();
51
78
52 const [query, setQuery] = useState('');
79 const [query, setQuery] = useState('');
53
80
54 useEffect(() => {
81 useEffect(() => {
55− points.map(syncInvites);
82+ acceptedPoints.map(syncInvites);
56− }, [points, syncInvites]);
83+ }, [acceptedPoints, syncInvites]);
57
84
58 const handleChange = useCallback(
85 const handleChange = useCallback(
59 e => {
86 e => {
@@ -63,40 +90,51 @@ function CohortList({ points, className }) {
63 [setQuery]
90 [setQuery]
64 );
91 );
65
92
66− const visiblePoints = useMemo(
93+ const filterPoints = useCallback(
67− () =>
94+ points =>
68 points.filter(p => {
95 points.filter(p => {
69 const patp = ob.patp(p).slice(1);
96 const patp = ob.patp(p).slice(1);
70 return patp.startsWith(query);
97 return patp.startsWith(query);
71 }),
98 }),
72− [query, points]
99+ [query]
73 );
100 );
74
101
75− return (
102+ const _pendingPoints = filterPoints(pendingPoints);
76− <Grid gap={3} className={cn('mt1', className)}>
103+ const _acceptedPoints = filterPoints(acceptedPoints);
77− <Grid.Item align="center" full as={Flex} className="b b-gray2 b1">
78− <Flex.Item className="p2">
79− <SearchIcon />
80− </Flex.Item>
81
104
82− <Flex.Item
105+ const offset = onlyPending ? 0 : _acceptedPoints.length;
83− flex={1}
106+
84− as={'input'}
107+ return (
85− value={query}
108+ <Grid gap={3} className={cn('mt4', className)}>
86− onChange={handleChange}
109+ <Grid.Item full as={SearchInput} value={query} onChange={handleChange} />
87− className="b-none h7"
88− />
89− </Grid.Item>
90 <>
110 <>
91− {visiblePoints.map((p, idx) => (
111+ {!onlyPending &&
112+ _acceptedPoints.map((p, idx) => (
113+ <Grid.Item
114+ key={p}
115+ half={(idx % 2) + 1}
92− <Grid.Item key={p} half={(idx % 2) + 1} as={CohortMember} point={p} />
116+ as={CohortMember}
117+ point={p}
118+ />
119+ ))}
120+ {_pendingPoints.map((p, idx) => (
121+ <Grid.Item
122+ key={p}
123+ half={((offset + idx) % 2) + 1}
124+ as={CohortMember}
125+ point={p}
126+ pending
127+ />
93 ))}
128 ))}
94 </>
129 </>
95− {visiblePoints.length === 0 && (
130+
131+ {_pendingPoints.length === 0 &&
132+ (_acceptedPoints.length === 0 || onlyPending) && (
96− <Grid.Item full className="p4 t-center">
133+ <Grid.Item full className="p4 t-center">
134+ {' '}
97− No invites accepted yet.
135+ No invites accepted yet.
98− </Grid.Item>
136+ </Grid.Item>
99− )}
137+ )}
100 </Grid>
138 </Grid>
101 );
139 );
102}
140}
@@ -116,6 +154,7 @@ export default function InviteCohort() {
116 } = useInvites(point);
154 } = useInvites(point);
117
155
118 const [showInviteForm, setShowInviteForm] = useState(false);
156 const [showInviteForm, setShowInviteForm] = useState(false);
157+ const [tab, setTab] = useState(NAMES.ALL);
119
158
120 const _acceptedPoints = acceptedPoints.getOrElse([]);
159 const _acceptedPoints = acceptedPoints.getOrElse([]);
121 const _pendingPoints = pendingPoints.getOrElse([]);
160 const _pendingPoints = pendingPoints.getOrElse([]);
@@ -170,8 +209,33 @@ export default function InviteCohort() {
170 )}
209 )}
171 {showInviteForm && <Inviter />}
210 {showInviteForm && <Inviter />}
172
211
212+ <Grid.Item
213+ full
214+ center
215+ as={Tabs}
216+ views={VIEWS}
217+ options={OPTIONS}
218+ currentTab={tab}
219+ onTabChange={setTab}
173− <Grid.Item full as={CohortList} points={_acceptedPoints} />
220+ acceptedPoints={_acceptedPoints}
221+ pendingPoints={_pendingPoints}
222+ onlyPending={tab === NAMES.PENDING}
223+ />
174 </Grid>
224 </Grid>
175 </View>
225 </View>
176 );
226 );
177}
227}
228+const NAMES = {
229+ ALL: 'ALL',
230+ PENDING: 'PENDING',
231+};
232+
233+const VIEWS = {
234+ [NAMES.PENDING]: CohortList,
235+ [NAMES.ALL]: CohortList,
236+};
237+
238+const OPTIONS = [
239+ { text: 'All', value: NAMES.ALL },
240+ { text: 'Pending', value: NAMES.PENDING },
241+];