1import React, { useMemo, useEffect, useCallback, useState } from 'react';
2import { Grid, Flex, Button } from 'indigo-react';
3import * as ob from 'urbit-ob';
4import { Just } from 'folktale/maybe';
5import cn from 'classnames';
7import { usePointCursor } from 'store/pointCursor';
8import { usePointCache } from 'store/pointCache';
10import View from 'components/View';
11import Tabs from 'components/Tabs';
12import BarGraph from 'components/BarGraph';
13import MaybeSigil from 'components/MaybeSigil';
14import { matchBlinky } from 'components/Blinky';
15import Chip from 'components/Chip';
16import Crumbs from 'components/Crumbs';
18import { useLocalRouter } from 'lib/LocalRouter';
19import useInvites from 'lib/useInvites';
20import * as need from 'lib/need';
22import Inviter from 'views/Invite/Inviter';
24import { ReactComponent as SearchIcon } from 'assets/search.svg';
25import NavHeader from 'components/NavHeader';
27function SearchInput({ className, value, onChange }) {
29 <Flex align="center" full className={cn('b b-gray2 b1', className)}>
30 <Flex.Item className="p2">
45function CohortMember({ point, pending = false, className }) {
46 const { sentInvites } = useInvites(point);
47 const patp = useMemo(() => ob.patp(point), [point]);
48 const colors = pending ? ['#ee892b', '#FFFFFF'] : ['#000000', '#FFFFFF'];
50 const DetailText = useCallback(
52 pending ? 'Pending' : <> {matchBlinky(sentInvites)} points invited </>,
53 [pending, sentInvites]
57 <Flex justify="between" className={cn('b1 b-gray2', className)}>
58 <Flex.Item className="w9 h9">
59 <MaybeSigil patp={Just(patp)} size={64} colors={colors} />
67 className="mono f6 ph4">
68 <Flex.Item>{patp}</Flex.Item>
69 <Flex.Item className="gray4">
76function CohortList({ acceptedPoints, pendingPoints, className, onlyPending }) {
77 const { syncInvites } = usePointCache();
79 const [query, setQuery] = useState('');
82 acceptedPoints.map(syncInvites);
83 }, [acceptedPoints, syncInvites]);
85 const handleChange = useCallback(
87 setQuery(e.target.value);
93 const filterPoints = useCallback(
96 const patp = ob.patp(p).slice(1);
97 return patp.startsWith(query);
102 const _pendingPoints = filterPoints(pendingPoints);
103 const _acceptedPoints = filterPoints(acceptedPoints);
105 const offset = onlyPending ? 0 : _acceptedPoints.length;
108 <Grid gap={3} className={cn('mt4', className)}>
109 <Grid.Item full as={SearchInput} value={query} onChange={handleChange} />
112 _acceptedPoints.map((p, idx) => (
120 {_pendingPoints.map((p, idx) => (
123 half={((offset + idx) % 2) + 1}
131 {_pendingPoints.length === 0 &&
132 (_acceptedPoints.length === 0 || onlyPending) && (
133 <Grid.Item full className="p4 t-center">
135 No invites accepted yet.
142export default function InviteCohort() {
143 const { pop } = useLocalRouter();
145 const { pointCursor } = usePointCursor();
146 const point = need.point(pointCursor);
154 } = useInvites(point);
156 const [showInviteForm, setShowInviteForm] = useState(false);
157 const [tab, setTab] = useState(NAMES.ALL);
159 const _acceptedPoints = acceptedPoints.getOrElse([]);
160 const _pendingPoints = pendingPoints.getOrElse([]);
161 const _pendingInvites = _pendingPoints.length;
162 const _acceptedInvites = _acceptedPoints.length;
163 const _totalInvites = availableInvites
164 .map(a => sentInvites.getOrElse(0) + a)
168 <View pop={pop} inset>
173 { text: ob.patp(point), action: () => pop() },
174 { text: 'Invite Group' },
179 <Grid.Item full>Invite Group</Grid.Item>
181 <Flex align="center">
183 {_acceptedInvites} / {_totalInvites}
185 {_pendingInvites !== 0 && (
186 <Flex.Item as={Chip} className="bg-yellow4 white">
187 {_pendingInvites} pending
195 available={availableInvites}
197 accepted={acceptedInvites}
199 {availableInvites.getOrElse(0) !== 0 && !showInviteForm && (
205 onClick={() => setShowInviteForm(true)}>
209 {showInviteForm && <Inviter />}
219 acceptedPoints={_acceptedPoints}
220 pendingPoints={_pendingPoints}
221 onlyPending={tab === NAMES.PENDING}
233 [NAMES.PENDING]: CohortList,
234 [NAMES.ALL]: CohortList,
238 { text: 'All', value: NAMES.ALL },
239 { text: 'Pending', value: NAMES.PENDING },
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list