on master help sign in
Updating L1 pending transaction styling
commitfa856b9ab9889cc02e55a51b1287832b59b533da authorWill Galebach <willbach@gmail.com> dateTue 14 Dec 2021, 15:38 (5 years ago) parent2bd4b28
19 files changed+404−277
src/components/InlineEthereumTransaction.js−1 src/components/L2/PendingTransaction.tsx−23 src/components/NetworkKeys.js+3−3 src/form/formatters.ts+14−12 src/lib/constants.ts+43−3 src/lib/router.js+1−1 src/lib/types/PendingL1Transaction.ts+10−8 src/views/AcceptTransfer.tsx+17−2 src/views/CancelTransfer.js → src/views/CancelTransfer.tsx+19−13 src/views/Point/IssueChild.tsx+2−1 src/views/Point/MigrateL2.tsx+1 src/views/Point/Point.tsx+17−11 src/views/Point/UrbitID.js+1−1 src/views/Transactions/TransactionHistory.scss+190−163 src/views/Transactions/TransactionRow.tsx+32−9 src/views/UrbitID/Home.tsx+1−1 src/views/UrbitID/SetProxy.js+2−1 src/views/UrbitID/Transfer.js → src/views/UrbitID/Transfer.tsx+50−24 src/views/UrbitOS/NetworkKeys.tsx+1
src/components/InlineEthereumTransaction.js−1
@@ -144,7 +144,6 @@ export default function InlineEthereumTransaction({
144144 className="eth-tx-button"
145145 full
146146 as={RestartButton}
147− center
148147 onClick={onReturn}>
149148 Return
150149 </Grid.Item>
src/components/L2/PendingTransaction.tsx−23
@@ -5,29 +5,6 @@ import LayerIndicator from './LayerIndicator';
55
66import './PendingTransaction.scss';
77
8−export const getPendingTitle = (type?: string) =>
9− type === 'set-management-proxy'
10− ? 'Management Address Changed'
11− : type === 'configure-keys'
12− ? 'Network Keys Configured'
13− : type === 'transfer-point'
14− ? 'Point Transfered'
15− : type === 'set-transfer-proxy'
16− ? 'Transfer Proxy Changed'
17− : type === 'set-spawn-proxy'
18− ? 'Spawn Proxy Changed'
19− : type === 'escape'
20− ? 'Change Sponsor'
21− : type === 'cancel-escape'
22− ? 'Cancel Escape'
23− : type === 'adopt'
24− ? 'Accept Sponsorship'
25− : type === 'reject'
26− ? 'Reject Sponsorship'
27− : type === 'detach'
28− ? 'Detach Sponsee'
29− : '';
30−
318export const getPendingL1Title = (type?: L1TxnType) =>
329 type === L1TxnType.setNetworkKeys
3310 ? 'Network Keys Configured'
src/components/NetworkKeys.js+3−3
@@ -14,7 +14,7 @@ const renderNetworkKey = key => {
1414 const segments = segmentNetworkKey(key);
1515
1616 if (!segments) {
17− return 'Unset';
17+ return 'Not set';
1818 }
1919
2020 return segments.join('\n');
@@ -40,7 +40,7 @@ export default function NetworkKeys({ point }) {
4040 {key.matchWith({
4141 Nothing: () => (
4242 <Grid.Item full as="code" className="f5 mono gray4">
43− Unset
43+ Not set
4444 </Grid.Item>
4545 ),
4646 Just: ({ value: key }) => (
@@ -65,7 +65,7 @@ export default function NetworkKeys({ point }) {
6565 {value.matchWith({
6666 Nothing: () => (
6767 <Flex.Item as={H5} className="f5 gray4">
68− Unset
68+ Not set
6969 </Flex.Item>
7070 ),
7171 Just: ({ value }) => <Flex.Item as={H5}>{value}</Flex.Item>,
src/form/formatters.ts+14−12
@@ -12,14 +12,14 @@ export const buildFormatter = (formatters = []) =>
1212/**
1313 * inserts a ~ or - before every pat block
1414 */
15−export const ensurePatFormat = s => {
15+export const ensurePatFormat = (s?: string) => {
1616 // bail if falsy or empty string, nothing to do
1717 if (!s || s.length === 0) {
1818 return s || '';
1919 }
2020
2121 // ensure there's a dash every 6 + 1 characters
22− const dashAt = i => i * (PAT_BLOCK_CHAR_LENGTH + 1);
22+ const dashAt = (i: number) => i * (PAT_BLOCK_CHAR_LENGTH + 1);
2323 const maxBlocks = TICKET_MAX_BYTE_LEN / 2;
2424
2525 // for every index that may need a separator
@@ -41,7 +41,7 @@ export const ensurePatFormat = s => {
4141 return s;
4242};
4343
44−export const ensureHexPrefix = s => {
44+export const ensureHexPrefix = (s?: string) => {
4545 if (!s || s.length < HEX_PREFIX.length) {
4646 return s || '';
4747 }
@@ -49,7 +49,7 @@ export const ensureHexPrefix = s => {
4949 return s.indexOf(HEX_PREFIX) !== 0 ? `${HEX_PREFIX}${s}` : s;
5050};
5151
52−export const convertToNumber = s => {
52+export const convertToNumber = (s?: string) => {
5353 if (!s) {
5454 return s || '';
5555 }
@@ -61,7 +61,7 @@ export const convertToNumber = s => {
6161 }
6262};
6363
64−export const downcase = s => {
64+export const downcase = (s?: string) => {
6565 if (!s) {
6666 return s;
6767 }
@@ -69,7 +69,7 @@ export const downcase = s => {
6969 return s.toLowerCase();
7070};
7171
72−export const stripHexPrefix = s => {
72+export const stripHexPrefix = (s?: string) => {
7373 if (!s) {
7474 return s;
7575 }
@@ -79,7 +79,7 @@ export const stripHexPrefix = s => {
7979 : s;
8080};
8181
82−export const ensureSigPrefix = s => {
82+export const ensureSigPrefix = (s?: string) => {
8383 if (!s || s.length < SIG_PREFIX.length) {
8484 return s || '';
8585 }
@@ -87,7 +87,7 @@ export const ensureSigPrefix = s => {
8787 return s.indexOf(SIG_PREFIX) !== 0 ? `${SIG_PREFIX}${s}` : s;
8888};
8989
90−export const stripSigPrefix = s => {
90+export const stripSigPrefix = (s: string) => {
9191 if (!s) {
9292 return s;
9393 }
@@ -113,9 +113,11 @@ export const capitalize = (s: string) => {
113113 return s.charAt(0).toUpperCase() + s.slice(1);
114114};
115115
116−export const titleize = (s: string): string => {
116+export const titleize = (s?: string): string => {
117117 return s
118− .split(' ')
119− .map(_s => capitalize(_s))
120− .join(' ');
118+ ? s
119+ .split(' ')
120+ .map(_s => capitalize(_s))
121+ .join(' ')
122+ : '';
121123};
src/lib/constants.ts+43−3
@@ -128,7 +128,14 @@ const INVITES_PER_PAGE = 7;
128128const DEFAULT_NUM_INVITES = 5;
129129const DEFAULT_CSV_NAME = 'urbit_invites.csv';
130130
131−const TRANSACTION_STATUS_ICONS = {
131+const TRANSACTION_STATUS_ICONS: {
132+ [key: string]:
133+ | 'Checkmark'
134+ | 'ArrowNorth'
135+ | 'Clock'
136+ | 'ExclaimationMark'
137+ | 'NullIcon';
138+} = {
132139 confirmed: 'Checkmark',
133140 pending: 'Clock',
134141 sending: 'ArrowNorth',
@@ -136,30 +143,63 @@ const TRANSACTION_STATUS_ICONS = {
136143 unknown: 'NullIcon',
137144};
138145
139−const TRANSACTION_TYPE_ICONS = {
146+const TRANSACTION_TYPE_ICONS: {
147+ [key: string]:
148+ | 'ArrowRefresh'
149+ | 'BootNode'
150+ | 'Delete'
151+ | 'EjectedSponsor'
152+ | 'EscapeApproved'
153+ | 'EscapeRejected'
154+ | 'EscapeRequested'
155+ | 'ShipSpawned'
156+ | 'Swap';
157+} = {
140158 adopt: 'EscapeApproved',
141159 'cancel-escape': 'EscapeRejected',
160+ 'cancel-transfer': 'Delete',
142161 'configure-keys': 'BootNode',
143162 detach: 'EjectedSponsor',
144163 escape: 'EscapeRequested',
164+ migrate: 'Swap',
145165 reject: 'EscapeRejected',
146166 'set-management-proxy': 'ArrowRefresh',
147167 'set-spawn-proxy': 'ArrowRefresh',
148168 'set-transfer-proxy': 'ArrowRefresh',
169+ 'set-voting-proxy': 'ArrowRefresh',
149170 spawn: 'ShipSpawned',
150171 'transfer-point': 'Swap',
151172};
152173
153−const TRANSACTION_TYPE_TITLES = {
174+const TRANSACTION_TYPE_TITLES: {
175+ [key: string]:
176+ | 'Ship Sponsored'
177+ | 'Escape Canceled'
178+ | 'Transfer Canceled'
179+ | 'Network Keys Configured'
180+ | 'Sponsee Detached'
181+ | 'Escaped Sponsor'
182+ | 'Migrating to Layer 2'
183+ | 'Sponsorship Rejected'
184+ | 'Management Proxy Changed'
185+ | 'Spawn Proxy Changed'
186+ | 'Transfer Proxy Changed'
187+ | 'Voting Proxy Changed'
188+ | 'Ship Spawned'
189+ | 'Ship Transferred';
190+} = {
154191 adopt: 'Ship Sponsored',
155192 'cancel-escape': 'Escape Canceled',
193+ 'cancel-transfer': 'Transfer Canceled',
156194 'configure-keys': 'Network Keys Configured',
157195 detach: 'Sponsee Detached',
158196 escape: 'Escaped Sponsor',
197+ migrate: 'Migrating to Layer 2',
159198 reject: 'Sponsorship Rejected',
160199 'set-management-proxy': 'Management Proxy Changed',
161200 'set-spawn-proxy': 'Spawn Proxy Changed',
162201 'set-transfer-proxy': 'Transfer Proxy Changed',
202+ 'set-voting-proxy': 'Voting Proxy Changed',
163203 spawn: 'Ship Spawned',
164204 'transfer-point': 'Ship Transferred',
165205};
src/lib/router.js+1−1
@@ -21,7 +21,7 @@ import IssueChild from 'views/Point/IssueChild';
2121import PartySetPoolSize from 'views/Party/PartySetPoolSize';
2222import InviteCohort from 'views/Invite/Cohort';
2323import AcceptTransfer from 'views/AcceptTransfer.tsx';
24−import CancelTransfer from 'views/CancelTransfer';
24+import CancelTransfer from 'views/CancelTransfer.tsx';
2525import Bitcoin from 'views/Bitcoin/Bitcoin';
2626import Xpub from 'views/Bitcoin/Xpub';
2727import SignTransaction from 'views/Bitcoin/SignTransaction';
src/lib/types/PendingL1Transaction.ts+10−8
@@ -1,13 +1,14 @@
11export enum L1TxnType {
22 migrate = 'migrate',
3− migrateSpawn = 'migrateSpawn',
4− spawnProxy = 'spawnProxy',
5− managementProxy = 'managementProxy',
6− transferProxy = 'transferProxy',
7− votingProxy = 'votingProxy',
8− acceptTransfer = 'acceptTransfer',
9− spawnPoint = 'spawnPoint',
10− setNetworkKeys = 'setNetworkKeys',
3+ migrateSpawn = 'migrate-spawn',
4+ spawnProxy = 'set-spawn-proxy',
5+ managementProxy = 'set-management-proxy',
6+ transferProxy = 'set-transfer-proxy',
7+ votingProxy = 'set-voting-proxy',
8+ acceptTransfer = 'transfer-point',
9+ cancelTransfer = 'cancel-transfer',
10+ spawn = 'spawn',
11+ setNetworkKeys = 'configure-keys',
1112}
1213
1314export interface PendingL1Txn {
@@ -15,6 +16,7 @@ export interface PendingL1Txn {
1516 point: number;
1617 type: L1TxnType;
1718 hash: string;
19+ time: number;
1820}
1921
2022export interface PendingL1 {
src/views/AcceptTransfer.tsx+17−2
@@ -14,6 +14,7 @@ import useCurrentPointName from 'lib/useCurrentPointName';
1414import useEthereumTransaction from 'lib/useEthereumTransaction';
1515import { GAS_LIMITS } from 'lib/constants';
1616import { useLocalRouter } from 'lib/LocalRouter';
17+import { L1TxnType } from 'lib/types/PendingL1Transaction';
1718
1819import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
1920import View from 'components/View';
@@ -40,7 +41,7 @@ function useAcceptTransfer() {
4041
4142 const transaction = useEthereumTransaction(
4243 useCallback(
43− reset =>
44+ (reset: boolean) =>
4445 azimuth.ecliptic.transferPoint(_contracts, _point, _address, reset),
4546 [_contracts, _point, _address]
4647 ),
@@ -69,13 +70,27 @@ export default function AcceptTransfer() {
6970
7071 const [reset, setReset] = useState(true);
7172
72− const { completed, bind, inputsLocked, construct } = useAcceptTransfer();
73+ const {
74+ completed,
75+ bind,
76+ inputsLocked,
77+ construct,
78+ txHashes,
79+ } = useAcceptTransfer();
7380
7481 useEffect(() => {
82+ // Update this one
7583 if (completed) {
7684 checkForUpdates({
7785 point: point.value,
7886 message: `${point.patp} has been transferred to you!`,
87+ l1Txn: {
88+ id: `accept-transfer-${point.value}`,
89+ point: point.value,
90+ type: L1TxnType.cancelTransfer,
91+ hash: txHashes[0],
92+ time: new Date().getTime(),
93+ },
7994 });
8095 }
8196 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
src/views/CancelTransfer.js → src/views/CancelTransfer.tsxrenamed+19−13
@@ -3,7 +3,6 @@ import cn from 'classnames';
33import { Grid, Text, Button } from 'indigo-react';
44import * as azimuth from 'azimuth-js';
55import { Nothing } from 'folktale/maybe';
6−import { Row } from '@tlon/indigo-react';
76
87import { useNetwork } from 'store/network';
98import { usePointCursor } from 'store/pointCursor';
@@ -17,6 +16,7 @@ import useEthereumTransaction from 'lib/useEthereumTransaction';
1716import { ETH_ZERO_ADDR, GAS_LIMITS } from 'lib/constants';
1817import useLifecycle from 'lib/useLifecycle';
1918import useRoller from 'lib/useRoller';
19+import { L1TxnType } from 'lib/types/PendingL1Transaction';
2020
2121import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
2222import View from 'components/View';
@@ -26,9 +26,9 @@ import BodyPane from 'components/L2/Window/BodyPane';
2626import L2BackHeader from 'components/L2/Headers/L2BackHeader';
2727
2828function useCancelTransfer() {
29− const { contracts } = useNetwork();
30− const { pointCursor } = usePointCursor();
31− const { syncDetails } = usePointCache();
29+ const { contracts }: any = useNetwork();
30+ const { pointCursor }: any = usePointCursor();
31+ const { syncDetails }: any = usePointCache();
3232
3333 const _contracts = need.contracts(contracts);
3434 const _point = need.point(pointCursor);
@@ -53,23 +53,30 @@ function useCancelTransfer() {
5353}
5454
5555function AdminCancelTransfer() {
56− const { pop } = useLocalRouter();
57− const { getDetails } = usePointCache();
56+ const { pop }: any = useLocalRouter();
57+ const { getDetails }: any = usePointCache();
5858 const { point } = useRollerStore();
5959 const { setProxyAddress, checkForUpdates } = useRoller();
60− const { pointCursor, setPointCursor } = usePointCursor();
60+ const { pointCursor, setPointCursor }: any = usePointCursor();
6161 const _point = need.point(pointCursor);
6262
6363 const name = useCurrentPointName();
6464 const _details = need.details(getDetails(_point));
6565
66− const { completed, bind } = useCancelTransfer();
66+ const { completed, bind, txHashes } = useCancelTransfer();
6767
6868 useEffect(() => {
6969 if (completed) {
7070 checkForUpdates({
7171 point: point.value,
7272 message: `${point.patp} transfer cancelled`,
73+ l1Txn: {
74+ id: `cancel-${point.value}`,
75+ point: point.value,
76+ type: L1TxnType.cancelTransfer,
77+ hash: txHashes[0],
78+ time: new Date().getTime(),
79+ },
7380 });
7481 }
7582 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
@@ -94,14 +101,13 @@ function AdminCancelTransfer() {
94101 return (
95102 <Window>
96103 <HeaderPane>
97− <Row className="header-row">
98− <h5>Cancel Outgoing Transfer</h5>
99− </Row>
104+ <h5>Cancel Outgoing Transfer</h5>
100105 </HeaderPane>
101106 <BodyPane>
102107 <Grid.Item
103108 full
104109 as={Text}
110+ style={{ fontSize: 14 }}
105111 className={cn('f5 wrap mb5', {
106112 green3: completed,
107113 })}>
@@ -139,8 +145,8 @@ function AdminCancelTransfer() {
139145}
140146
141147export default function CancelTransfer() {
142− const { pop } = useLocalRouter();
143− const { setPointCursor } = usePointCursor();
148+ const { pop }: any = useLocalRouter();
149+ const { setPointCursor }: any = usePointCursor();
144150
145151 const goBack = useCallback(() => {
146152 setPointCursor(Nothing());
src/views/Point/IssueChild.tsx+2−1
@@ -144,8 +144,9 @@ export default function IssueChild() {
144144 l1Txn: {
145145 id: `${pointToSpawn}`,
146146 point: point.value,
147− type: L1TxnType.spawnPoint,
147+ type: L1TxnType.spawn,
148148 hash: txHashes[0],
149+ time: new Date().getTime(),
149150 },
150151 });
151152 }
src/views/Point/MigrateL2.tsx+1
@@ -144,6 +144,7 @@ export default function MigrateL2() {
144144 point: selectedPoint.value,
145145 type: transfer ? L1TxnType.migrate : L1TxnType.migrateSpawn,
146146 hash: txHashes[0],
147+ time: new Date().getTime(),
147148 },
148149 });
149150
src/views/Point/Point.tsx+17−11
@@ -23,10 +23,10 @@ import { useHasNetworkKeysSet } from 'lib/useHasNetworkKeysSet';
2323import LoadingOverlay from 'components/L2/LoadingOverlay';
2424import PendingTransaction, {
2525 getPendingL1Title,
26− getPendingTitle,
2726} from 'components/L2/PendingTransaction';
2827import Modal from 'components/L2/Modal';
2928import './Point.scss';
29+import { TransactionRow } from 'views/Transactions/TransactionRow';
3030
3131export default function Point() {
3232 const { pop, push, names }: any = useLocalRouter();
@@ -131,21 +131,27 @@ export default function Point() {
131131 />
132132 )}
133133 {!!otherPending.length &&
134− otherPending.map((pendingTx, ind) => (
135− <PendingTransaction
136− key={`pending-tx-${ind}`}
137− layer={2}
138− nextRoll={nextRoll}
139− title={getPendingTitle(pendingTx.rawTx?.tx?.type)}
134+ otherPending.map(pendingTx => (
135+ <TransactionRow
136+ className="point-view"
137+ key={pendingTx.time}
138+ ship={point.patp}
139+ type={pendingTx.rawTx?.tx?.type}
140+ status="pending"
141+ time={pendingTx.time}
140142 />
141143 ))}
142144 {!!pendingL1Transactions.length &&
143145 pendingL1Transactions.map((pendingTx, ind) => (
144− <PendingTransaction
145− key={`pending-tx-${ind}`}
146− layer={1}
146+ <TransactionRow
147+ className="point-view"
148+ key={pendingTx.time}
149+ ship={point.patp}
150+ type={pendingTx.type as string}
151+ status="pending"
152+ time={pendingTx.time}
147153 hash={pendingTx.hash}
148− title={getPendingL1Title(pendingTx.type)}
154+ layer={1}
149155 />
150156 ))}
151157 <Passport
src/views/Point/UrbitID.js+1−1
@@ -14,7 +14,7 @@ import SigilGenerator from '../UrbitID/SigilGenerator';
1414import DownloadKeys from '../UrbitID/DownloadKeys';
1515import SetProxy from '../UrbitID/SetProxy';
1616import ResetKeys from '../UrbitID/ResetKeys';
17−import Transfer from '../UrbitID/Transfer';
17+import Transfer from '../UrbitID/Transfer.tsx';
1818
1919const NAMES = {
2020 HOME: 'HOME',
src/views/Transactions/TransactionHistory.scss+190−163
@@ -91,216 +91,243 @@
9191 display: none; /* Chrome */
9292 }
9393 }
94+}
9495
95− .address-row {
96− @include tx-row();
96+.address-row {
97+ @include tx-row();
9798
98− .icon {
99− grid-area: icon;
100− background-color: black;
101− border-radius: 2px;
102− width: 24px;
103− height: 24px;
104− }
99+ .icon {
100+ grid-area: icon;
101+ background-color: black;
102+ border-radius: 2px;
103+ width: 24px;
104+ height: 24px;
105+ }
105106
106− .info {
107− grid-area: info;
108− display: flex;
109− flex-flow: column nowrap;
110− justify-content: center;
107+ .info {
108+ grid-area: info;
109+ display: flex;
110+ flex-flow: column nowrap;
111+ justify-content: center;
111112
112− .address {
113− font-family: Source Code Pro;
114− font-size: 14px;
115− font-style: normal;
116− font-weight: 500;
117− line-height: 16px;
118− letter-spacing: 0em;
119− }
113+ .address {
114+ font-family: Source Code Pro;
115+ font-size: 14px;
116+ font-style: normal;
117+ font-weight: 500;
118+ line-height: 16px;
119+ letter-spacing: 0em;
120120 }
121121 }
122+}
122123
123− .patp-row {
124− @include tx-row();
124+.patp-row {
125+ @include tx-row();
125126
126− .icon {
127− grid-area: icon;
128−
129− .sigil {
130− background-color: black;
131− border-radius: 2px;
132− padding: 6px;
133− }
127+ .icon {
128+ grid-area: icon;
129+
130+ .sigil {
131+ background-color: black;
132+ border-radius: 2px;
133+ padding: 6px;
134134 }
135+ }
135136
136− .info {
137− grid-area: info;
138− display: flex;
139− flex-flow: column nowrap;
140− justify-content: center;
137+ .info {
138+ grid-area: info;
139+ display: flex;
140+ flex-flow: column nowrap;
141+ justify-content: center;
141142
142− .patp {
143− font-family: Source Code Pro;
144− font-size: 14px;
145− font-style: normal;
146− font-weight: 500;
147− line-height: 16px;
148− letter-spacing: 0em;
149− }
143+ .patp {
144+ font-family: Source Code Pro;
145+ font-size: 14px;
146+ font-style: normal;
147+ font-weight: 500;
148+ line-height: 16px;
149+ letter-spacing: 0em;
150150 }
151151 }
152+}
153+
154+.transaction-row {
155+ @include tx-row();
152156
153− .transaction-row {
154− @include tx-row();
157+ &.point-view {
158+ padding: 8px;
159+ border: 1px solid $light-gray;
160+ border-radius: $large-border-radius;
161+ margin-bottom: 16px;
162+ }
155163
156− .icon {
157− grid-area: icon;
158− padding-top: 6px;
164+ .icon {
165+ grid-area: icon;
166+ padding-top: 6px;
159167
160− svg {
161− height: 16px;
162− width: 16px;
163− }
168+ svg {
169+ height: 16px;
170+ width: 16px;
164171 }
172+ }
165173
166− .info {
167− grid-area: info;
174+ .info {
175+ grid-area: info;
176+ }
177+
178+ .title-row {
179+ display: flex;
180+ flex-direction: row;
181+ justify-content: space-between;
182+ align-items: center;
183+ margin-bottom: 8px;
184+
185+ .title {
186+ font-family: Inter;
187+ font-size: 14px;
188+ font-style: normal;
189+ font-weight: 400;
190+ line-height: 24px;
191+ letter-spacing: -0.011em;
168192 }
169193
170− .title-row {
171− display: flex;
172− flex-direction: row;
173− justify-content: space-between;
174− align-items: center;
175− margin-bottom: 8px;
176−
177− .title {
194+ .status {
195+ .badge {
196+ align-items: center;
197+ background-color: black;
198+ border-radius: 2px;
199+ color: white;
200+ display: flex;
201+ flex-flow: row nowrap;
178202 font-family: Inter;
179203 font-size: 14px;
180204 font-style: normal;
181− font-weight: 400;
182− line-height: 24px;
183− letter-spacing: -0.011em;
184− }
205+ font-weight: 500;
206+ justify-content: space-between;
207+ letter-spacing: 0em;
208+ line-height: 18px;
209+ padding: 4px 8px;
210+ text-align: center;
211+ width: 78px;
212+
213+ svg {
214+ height: 14px;
215+ width: 14px;
216+ padding-top: 4px;
217+ path {
218+ fill: white;
219+ }
220+ }
185221
186− .status {
187− .badge {
188− align-items: center;
189− background-color: black;
190− border-radius: 2px;
191− color: white;
192− display: flex;
193− flex-flow: row nowrap;
194− font-family: Inter;
195− font-size: 14px;
196− font-style: normal;
197− font-weight: 500;
198− justify-content: space-between;
199− letter-spacing: 0em;
200− line-height: 18px;
201− padding: 4px 8px;
202− text-align: center;
203− width: 78px;
222+ &.confirmed {
223+ width: 92px;
224+ background: #009F65;
225+ }
226+
227+ &.sending {
228+ width: 74px;
229+ background: #00000033;
230+ color: black;
204231
205232 svg {
206− height: 14px;
207− width: 14px;
208− padding-top: 4px;
209233 path {
210− fill: white;
234+ fill: black;
211235 }
212236 }
237+ }
213238
214− &.confirmed {
215− width: 92px;
216− background: #009F65;
217− }
218−
219− &.sending {
220− width: 74px;
221− background: #00000033;
222− color: black;
239+ &.failed {
240+ background-color: rgb(246,200,196);
241+ color: rgb(236,81,66);
242+ width: 62px;
223243
224− svg {
225− path {
226− fill: black;
227− }
228− }
244+ span.icon-wrapper {
245+ height: 16px;
246+ width: 16px;
247+ border-radius: 50%;
248+ background-color: #FF4136;
229249 }
230250
231− &.failed {
232− background-color: rgb(246,200,196);
233− color: rgb(236,81,66);
234− width: 62px;
235−
236− span.icon-wrapper {
237− height: 16px;
238− width: 16px;
239− border-radius: 50%;
240− background-color: #FF4136;
241− }
242−
243− svg {
244− padding-top: 1px;
245−
246− path {
247− fill: white;
248− }
251+ svg {
252+ padding-top: 1px;
253+
254+ path {
255+ fill: white;
249256 }
250257 }
258+ }
251259
252− &.pending {
253− background-color: $rollup-yellow;
254− color: #000;
255− width: 100px;
256− width: 105px;
257−
258− svg {
259− path {
260− fill: #000;
261− }
260+ &.pending {
261+ background-color: $rollup-yellow;
262+ color: #000;
263+ width: 100px;
264+ width: 105px;
265+
266+ svg {
267+ path {
268+ fill: #000;
262269 }
263270 }
271+ }
264272
265− &.unknown {
266− width: 82px;
267− }
273+ &.unknown {
274+ width: 82px;
268275 }
269276 }
270277 }
271−
272− .info-row {
278+ }
279+
280+ .info-row {
281+ display: flex;
282+ flex-direction: row;
283+ justify-content: space-between;
284+ align-items: center;
285+
286+ .hash-container {
273287 display: flex;
274− flex-direction: row;
288+ flex-flow: row nowrap;
275289 justify-content: space-between;
276290 align-items: center;
291+ width: 31%;
277292
278− .hash-container {
279− display: flex;
280− flex-flow: row nowrap;
281− justify-content: space-between;
282− align-items: center;
283− width: 31%;
284− }
285−
286− .hash {
287− font-family: Source Code Pro;
293+ .etherscan {
288294 font-size: 14px;
289− font-style: normal;
290− font-weight: 400;
291− line-height: 16px;
292− letter-spacing: -0.011em;
293− color: rgba(0,0,0,0.6);
295+ color: $dark-gray;
296+
297+ svg {
298+ height: 18px;
299+ width: 18px;
300+ margin-bottom: -4px;
301+ -ms-transform:rotate(315deg); /* IE9 */
302+ -moz-transform: rotate(315deg); /* FF3.5/3.6 */
303+ -o-transform: rotate(315deg); /* Opera 10.5 */
304+ -webkit-transform: rotate(315deg); /* Saf3.1+ */
305+ transform: rotate(315deg); /* Newer browsers */
306+
307+ path {
308+ fill: $dark-gray;
309+ }
310+ }
294311 }
312+ }
295313
296− .date {
297− font-family: Inter;
298− font-size: 14px;
299− font-style: normal;
300− font-weight: 400;
301− line-height: 16px;
302− letter-spacing: -0.011em;
303− }
314+ .hash {
315+ font-family: Source Code Pro;
316+ font-size: 14px;
317+ font-style: normal;
318+ font-weight: 400;
319+ line-height: 16px;
320+ letter-spacing: -0.011em;
321+ color: rgba(0,0,0,0.6);
304322 }
305− }
306−}
323+
324+ .date {
325+ font-family: Inter;
326+ font-size: 14px;
327+ font-style: normal;
328+ font-weight: 400;
329+ line-height: 16px;
330+ letter-spacing: -0.011em;
331+ }
332+ }
333+}
src/views/Transactions/TransactionRow.tsx+32−9
@@ -15,14 +15,22 @@ import { abbreviateAddress } from 'lib/utils/address';
1515import { isPlanet, isStar } from 'lib/utils/point';
1616import { titleize } from 'form/formatters';
1717import LayerIndicator from 'components/L2/LayerIndicator';
18+import { useExploreTxUrl } from 'lib/explorer';
19+
20+interface TransactionRowProps extends RollerTransaction {
21+ className?: string;
22+ layer?: 1 | 2;
23+}
1824
1925export const TransactionRow = ({
26+ className = '',
2027 ship,
21− type,
28+ type = '',
2229 hash,
23− status,
30+ status = 'pending',
2431 time,
25−}: RollerTransaction) => {
32+ layer = 2,
33+}: TransactionRowProps) => {
2634 const { nextRoll } = useTimerStore();
2735
2836 // For spawn events (associated with the spawner), we want to show the spawnee tier;
@@ -70,7 +78,7 @@ export const TransactionRow = ({
7078
7179 const longDate = useMemo(() => {
7280 if (!parsedDate) {
73− return null;
81+ return;
7482 }
7583
7684 return parsedDate.toISOString();
@@ -82,13 +90,17 @@ export const TransactionRow = ({
8290 <span className={'icon-wrapper'}>
8391 <Icon icon={TRANSACTION_STATUS_ICONS[status] || 'Bug'} />
8492 </span>
85− <span>{status === 'pending' ? nextRoll : titleize(status)}</span>
93+ <span>
94+ {status === 'pending' && layer === 2 ? nextRoll : titleize(status)}
95+ </span>
8696 </div>
8797 );
88− }, [nextRoll, status]);
98+ }, [nextRoll, status, layer]);
99+
100+ const txHash = useExploreTxUrl(hash);
89101
90102 return (
91− <Box className="transaction-row">
103+ <Box className={`transaction-row ${className}`}>
92104 <Box className="icon">{icon}</Box>
93105 <Box className="info">
94106 <Row className="title-row">
@@ -97,8 +109,19 @@ export const TransactionRow = ({
97109 </Row>
98110 <Row className="info-row">
99111 <Box className="hash-container">
100− <Box className="hash">{shortHash}</Box>
101− <LayerIndicator layer={2} size={'sm'} />
112+ {layer === 1 ? (
113+ <a
114+ className="etherscan"
115+ href={txHash}
116+ rel="noreferrer"
117+ target="_blank">
118+ Etherscan
119+ <Icon className="arrow" icon="ArrowEast" />
120+ </a>
121+ ) : (
122+ !!hash && <Box className="hash">{shortHash}</Box>
123+ )}
124+ <LayerIndicator layer={layer} size={'sm'} />
102125 </Box>
103126 <Box className="date" title={longDate}>
104127 {shortDate}
src/views/UrbitID/Home.tsx+1−1
@@ -136,7 +136,7 @@ export default function UrbitIDHome() {
136136 <Box>
137137 <Box>Spawn Proxy Address</Box>
138138 <div className="mt1 mono black subtitle">
139− {noSpawn ? 'Unset' : abbreviateAddress(point.spawnProxy)}
139+ {noSpawn ? 'Not set' : abbreviateAddress(point.spawnProxy)}
140140 </div>
141141 </Box>
142142 <Row>
src/views/UrbitID/SetProxy.js+2−1
@@ -198,6 +198,7 @@ export default function SetProxy() {
198198 point: point.value,
199199 type: proxyTypeToL1TxnType(data.proxyType),
200200 hash: txHashes[0],
201+ time: new Date().getTime(),
201202 },
202203 });
203204 }
@@ -289,7 +290,7 @@ export default function SetProxy() {
289290 gray4: !completed && !isProxySet,
290291 green3: completed,
291292 })}>
292− {isProxySet ? proxyAddress : 'Unset'}
293+ {isProxySet ? proxyAddress : 'Not set'}
293294 </Flex.Item>
294295 </Grid.Item>
295296
src/views/UrbitID/Transfer.js → src/views/UrbitID/Transfer.tsxrenamed+50−24
@@ -1,8 +1,6 @@
1−import React, { useCallback, useMemo, useState } from 'react';
2−import cn from 'classnames';
1+import React, { useCallback, useEffect, useMemo, useState } from 'react';
32import { Grid, Text, Button } from 'indigo-react';
43import * as azimuth from 'azimuth-js';
5−import { Row } from '@tlon/indigo-react';
64
75import { useNetwork } from 'store/network';
86import { usePointCursor } from 'store/pointCursor';
@@ -26,18 +24,20 @@ import FormError from 'form/FormError';
2624import Window from 'components/L2/Window/Window';
2725import HeaderPane from 'components/L2/Window/HeaderPane';
2826import BodyPane from 'components/L2/Window/BodyPane';
27+import { L1TxnType } from 'lib/types/PendingL1Transaction';
2928
3029function useTransfer() {
31− const { contracts } = useNetwork();
32− const { pointCursor } = usePointCursor();
33− const { syncDetails } = usePointCache();
30+ const { contracts }: any = useNetwork();
31+ const { pointCursor }: any = usePointCursor();
32+ const { syncDetails }: any = usePointCache();
3433
3534 const _contracts = need.contracts(contracts);
3635 const _point = need.point(pointCursor);
3736
3837 return useEthereumTransaction(
3938 useCallback(
40− address => azimuth.ecliptic.setTransferProxy(_contracts, _point, address),
39+ (address: string) =>
40+ azimuth.ecliptic.setTransferProxy(_contracts, _point, address),
4141 [_contracts, _point]
4242 ),
4343 useCallback(() => syncDetails(_point), [_point, syncDetails]),
@@ -46,14 +46,15 @@ function useTransfer() {
4646}
4747
4848export default function AdminTransfer() {
49− const { pop } = useLocalRouter();
49+ const { pop }: any = useLocalRouter();
5050 const name = useCurrentPointName();
51− const { pointCursor } = usePointCursor();
52− const { starReleaseDetails } = useStarReleaseCache();
51+ const { starReleaseDetails }: any = useStarReleaseCache();
52+ const { point } = useRollerStore();
5353 const {
54− point: { isL2 },
55− } = useRollerStore();
56− const { setProxyAddress, getPendingTransactions } = useRoller();
54+ setProxyAddress,
55+ getPendingTransactions,
56+ checkForUpdates,
57+ } = useRoller();
5758 const [owner, setNewOwner] = useState('');
5859
5960 const {
@@ -62,18 +63,34 @@ export default function AdminTransfer() {
6263 completed,
6364 inputsLocked,
6465 bind,
66+ txHashes,
6567 } = useTransfer();
6668
67− const point = need.point(pointCursor);
68−
6969 const needLockupWarning = useMemo(() => {
7070 const az = azimuth.azimuth;
7171 return (
72− az.getPointSize(point) === az.PointSize.Galaxy &&
73− starReleaseDetails.map(a => a.kind).getOrElse('none') !== 'none'
72+ az.getPointSize(point.value) === az.PointSize.Galaxy &&
73+ starReleaseDetails.map((a: any) => a.kind).getOrElse('none') !== 'none'
7474 );
7575 }, [starReleaseDetails, point]);
7676
77+ useEffect(() => {
78+ // Update this one
79+ if (completed) {
80+ checkForUpdates({
81+ point: point.value,
82+ message: `${point.patp}'s transfer proxy has been set!`,
83+ l1Txn: {
84+ id: `set-transfer-proxy-${point.value}`,
85+ point: point.value,
86+ type: L1TxnType.transferProxy,
87+ hash: txHashes[0],
88+ time: new Date().getTime(),
89+ },
90+ });
91+ }
92+ }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
93+
7794 const validate = useMemo(
7895 () => composeValidator({ address: buildAddressValidator() }),
7996 []
@@ -84,14 +101,25 @@ export default function AdminTransfer() {
84101 if (owner === '') return;
85102 try {
86103 await setProxyAddress('transfer', owner);
87− getPendingTransactions(point);
104+ getPendingTransactions();
105+ checkForUpdates({
106+ point: point.value,
107+ message: `${point.patp}'s transfer proxy has been set!`,
108+ });
88109 pop();
89110 } catch (error) {
90111 // setError(error);
91112 } finally {
92113 // setLoading(false);
93114 }
94− }, [owner, getPendingTransactions, point, pop, setProxyAddress]);
115+ }, [
116+ point,
117+ owner,
118+ getPendingTransactions,
119+ pop,
120+ setProxyAddress,
121+ checkForUpdates,
122+ ]);
95123
96124 const onValues = useCallback(
97125 ({ valid, values }) => {
@@ -109,9 +137,7 @@ export default function AdminTransfer() {
109137 return (
110138 <Window>
111139 <HeaderPane>
112− <Row className="header-row">
113− <h5>Transfer Point</h5>
114− </Row>
140+ <h5>Transfer Point</h5>
115141 </HeaderPane>
116142 <BodyPane>
117143 <Grid className="w-full" full gap={1}>
@@ -119,7 +145,7 @@ export default function AdminTransfer() {
119145 {({ handleSubmit, values }) => (
120146 <>
121147 {!completed && (
122− <Grid.Item full as={Text} className={cn('f5 wrap')}>
148+ <Grid.Item full as={Text} style={{ fontSize: 14 }}>
123149 Transfer <span className="mono">{name}</span> to a new
124150 owner.
125151 </Grid.Item>
@@ -160,7 +186,7 @@ export default function AdminTransfer() {
160186
161187 <Grid.Item full as={FormError} />
162188
163− {isL2 ? (
189+ {point.isL2 ? (
164190 <Grid.Item
165191 as={Button}
166192 full
src/views/UrbitOS/NetworkKeys.tsx+1
@@ -189,6 +189,7 @@ export default function UrbitOSNetworkKeys({
189189 point: point.value,
190190 type: L1TxnType.setNetworkKeys,
191191 hash: txHashes[0],
192+ time: new Date().getTime(),
192193 },
193194 });
194195 }