on master help sign in
ux: filter TXs by patp

- add loading state indicator - remove test Gallery component

commit8b8af6e7f362f2e833208c793bed038de4d21147 authortomholford <tomholford@users.noreply.github.com> dateTue 12 Oct 2021, 09:55 (5 years ago) parent1b43863
5 files changed+150−52
src/form/formatters.ts+4 src/views/Transactions/Gallery.tsx−20 src/views/Transactions/ShipRow.tsx → src/views/Transactions/PatpRow.tsx+3−3 src/views/Transactions/TransactionHistory.scss+59−1 src/views/Transactions/TransactionHistory.tsx+84−28
src/form/formatters.ts+4
@@ -106,6 +106,10 @@ export const ticketFromSegments = (segments: string[]): string => {
106106};
107107
108108export const capitalize = (s: string) => {
109+ if (!s || s === '') {
110+ return s;
111+ }
112+
109113 return s.charAt(0).toUpperCase() + s.slice(1);
110114};
111115
src/views/Transactions/Gallery.tsxdeleted−20
@@ -1,20 +0,0 @@
1−import { Box, Icon } from '@tlon/indigo-react';
2−import { _iconIndex as iconIndex } from '@tlon/indigo-react';
3−
4−export const Gallery = () => {
5− const iconNames = Object.keys(iconIndex);
6− return (
7− <>
8− {iconNames.map(name => {
9− return (
10− <>
11− <Box padding={'5px'} marginBottom={'5px'} border={'solid 1px rgba(0,0,0,0.5)'}>
12− {name}
13− <Icon icon={name} height={'16px'} width={'16px'} />
14− </Box>
15− </>
16− );
17− })}
18− </>
19− );
20−};
src/views/Transactions/ShipRow.tsx → src/views/Transactions/PatpRow.tsxrenamed+3−3
@@ -1,10 +1,10 @@
1−import { Box, Row } from '@tlon/indigo-react';
1+import { Box } from '@tlon/indigo-react';
22import Sigil from 'components/Sigil';
33
4−export const ShipRow = ({ patp }) => {
4+export const PatpRow = ({ patp }) => {
55 return (
66 <>
7− <Box className="ship-row">
7+ <Box className="patp-row">
88 <Box className="icon">
99 <Box className="sigil">
1010 {
src/views/Transactions/TransactionHistory.scss+59−1
@@ -14,11 +14,69 @@
1414
1515.transaction-history {
1616
17+ .loading {
18+ width: 100%;
19+ min-height: 400px;
20+ display: flex;
21+ flex-flow: column nowrap;
22+ justify-content: center;
23+ align-items: center;
24+ color: rgba(0,0,0,0.6);
25+ }
26+
27+ .transaction-header {
28+ display: flex;
29+ flex-flow: row nowrap;
30+ justify-content: space-between;
31+ width: 100%;
32+ }
33+
34+ .transaction-dropdown {
35+ font-size: 14px;
36+ position: relative;
37+
38+ .selector {
39+ font-family: "Source Code Pro", "Roboto mono", "Courier New", monospace;
40+ }
41+
42+ .content-border {
43+ .dropdown-content {
44+ .entry, .current-address {
45+ display: flex;
46+ flex-direction: row;
47+ justify-content: space-between;
48+ align-items: center;
49+ cursor: pointer;
50+
51+ padding: 8px 12px 8px 16px;
52+
53+ &:hover {
54+ opacity: 0.8;
55+ }
56+
57+ .sigil {
58+ background-color: black;
59+ height: 14px;
60+ width: 14px;
61+ padding: 4px;
62+ border-radius: $small-border-radius;
63+ }
64+ }
65+
66+ .divider {
67+ width: 100%;
68+ height: 1px;
69+ background-color: $light-gray;
70+ }
71+ }
72+ }
73+ }
74+
1775 .transaction-container {
1876 width: 100%;
1977 }
2078
21− .ship-row {
79+ .patp-row {
2280 @include tx-row();
2381
2482 .icon {
src/views/Transactions/TransactionHistory.tsx+84−28
@@ -14,8 +14,10 @@ import { RollerTransaction } from '@urbit/roller-api';
1414
1515import './TransactionHistory.scss';
1616import { TransactionRow } from './TransactionRow';
17−import { Box } from '@tlon/indigo-react';
18−import { ShipRow } from './ShipRow';
17+import { Box, Row } from '@tlon/indigo-react';
18+import { PatpRow } from './PatpRow';
19+import Dropdown from 'components/L2/Dropdowns/Dropdown';
20+import Sigil from 'components/Sigil';
1921
2022interface GroupedTransactions {
2123 [ship: string]: RollerTransaction[];
@@ -26,7 +28,21 @@ const TransactionHistory = () => {
2628 const { api } = useRoller();
2729 const { wallet }: any = useWallet();
2830 const address = need.addressFromWallet(wallet);
31+ const [loading, setLoading] = useState(true);
2932 const [transactions, setTransactions] = useState<RollerTransaction[]>([]);
33+ const [dropdownOpen, setDropdownOpen] = useState<boolean>(false);
34+ const [selectedPatp, setSelectedPatp] = useState<string | null>(null);
35+
36+ const fetchTransactions = useCallback(async () => {
37+ const txns = await api.getHistory(address);
38+ setTransactions(txns);
39+ setLoading(false);
40+ }, [address, api]);
41+
42+ const selectPatp = useCallback(patp => {
43+ setSelectedPatp(patp);
44+ setDropdownOpen(false);
45+ }, []);
3046
3147 const txnsByPatp = useMemo(() => {
3248 return transactions.reduce((memo, tx) => {
@@ -39,14 +55,17 @@ const TransactionHistory = () => {
3955 }, {} as GroupedTransactions);
4056 }, [transactions]);
4157
42− const txKeys = useMemo(() => {
58+ const txPatps = useMemo(() => {
4359 return Object.keys(txnsByPatp).sort();
4460 }, [txnsByPatp]);
4561
46− const fetchTransactions = useCallback(async () => {
47− const txns = await api.getHistory(address);
48− setTransactions(txns);
49− }, [address, api]);
62+ const filteredPatps = useMemo(() => {
63+ if (!selectedPatp) {
64+ return txPatps;
65+ }
66+
67+ return txPatps.filter(p => p === selectedPatp);
68+ }, [selectedPatp, txPatps]);
5069
5170 useEffect(() => {
5271 fetchTransactions();
@@ -60,27 +79,64 @@ const TransactionHistory = () => {
6079 className="transaction-history"
6180 header={<L2BackHeader />}>
6281 <Window>
63− <HeaderPane>
64− <h5>Transactions</h5>
65− </HeaderPane>
66− <BodyPane>
67− <Box className="transaction-container">
68− {txKeys.map(patp => {
69− return (
70− <>
71− <ShipRow patp={patp} />
72− {txnsByPatp[patp]
73− .sort((a, b) => {
74− return a.time - b.time;
75− })
76− .map(tx => (
77− <TransactionRow key={tx.time} {...tx} />
78− ))}
79− </>
80− );
81− })}
82− </Box>
83− </BodyPane>
82+ {loading ? (
83+ <Box className={'loading'}>Loading...</Box>
84+ ) : (
85+ <>
86+ <HeaderPane>
87+ <Box className="transaction-header">
88+ <h5>Transactions</h5>
89+ <Dropdown
90+ className="transaction-dropdown"
91+ open={dropdownOpen}
92+ value={selectedPatp}
93+ toggleOpen={() => setDropdownOpen(!dropdownOpen)}>
94+ <Box className="divider" />
95+ <Box className="points">
96+ {txPatps.map(patp => {
97+ return (
98+ <Row
99+ className="entry"
100+ onClick={() => selectPatp(patp)}
101+ key={patp}>
102+ <Box>{patp}</Box>
103+ <Row>
104+ <Box className="sigil">
105+ <Sigil
106+ icon
107+ patp={patp}
108+ size={1}
109+ colors={['#000', '#FFF']}
110+ />
111+ </Box>
112+ </Row>
113+ </Row>
114+ );
115+ })}
116+ </Box>
117+ </Dropdown>
118+ </Box>
119+ </HeaderPane>
120+ <BodyPane>
121+ <Box className="transaction-container">
122+ {filteredPatps.map(patp => {
123+ return (
124+ <Box key={patp}>
125+ <PatpRow patp={patp} />
126+ {txnsByPatp[patp]
127+ .sort((a, b) => {
128+ return a.time - b.time;
129+ })
130+ .map(tx => (
131+ <TransactionRow key={tx.time} {...tx} />
132+ ))}
133+ </Box>
134+ );
135+ })}
136+ </Box>
137+ </BodyPane>
138+ </>
139+ )}
84140 </Window>
85141 </View>
86142 );