on master help sign in
Fixup janky UI/UX
f5ddd09Liam Fitzgerald
src/components/InlineEthereumTransaction.js+2−6
@@ -289,13 +289,9 @@ function HashReceiptList({ txHashes }) {
289
289
290 {txHashes &&
290 {txHashes &&
291 txHashes.map((txHash, i) => (
291 txHashes.map((txHash, i) => (
292− <Flex.Item className="mb3" as={Flex}>
292+ <Flex.Item key={i} className="mb3" as={Flex}>
293 <>
293 <>
294− <Flex.Item
295− key={i}
296− flex
297− as="code"
298− className="f6 mono gray4 wrap mr3">
294+ <Flex.Item flex as="code" className="f6 mono gray4 wrap mr3">
299 {txHash}
295 {txHash}
300 </Flex.Item>
296 </Flex.Item>
301 <Flex.Item as={LinkButton} href={txUrls[i]}>
297 <Flex.Item as={LinkButton} href={txUrls[i]}>
src/indigo-react/indigo.css+3
@@ -3397,6 +3397,9 @@ caption,
3397.h-auto {
3397.h-auto {
3398 height: auto; }
3398 height: auto; }
3399
3399
3400+.h-full {
3401+ height: 100%; }
3402+
3400@media only screen and (min-width: 550px) {
3403@media only screen and (min-width: 550px) {
3401 .h-auto-ns {
3404 .h-auto-ns {
3402 height: auto; } }
3405 height: auto; } }
src/lib/starRelease.js−1
@@ -1,5 +1,4 @@
1import { linearSR, conditionalSR } from 'azimuth-js';
1import { linearSR, conditionalSR } from 'azimuth-js';
2−import { Just, Nothing } from 'folktale/maybe';
3
2
4function mapRange(amount, cb) {
3function mapRange(amount, cb) {
5 return [...Array(amount).keys()].map(cb);
4 return [...Array(amount).keys()].map(cb);
src/views/Release.js+9−3
@@ -1,5 +1,5 @@
1import React, { useState, useCallback } from 'react';
1import React, { useState, useCallback } from 'react';
2−import { H4, Grid } from 'indigo-react';
2+import { H1, Grid } from 'indigo-react';
3import { Just } from 'folktale/maybe';
3import { Just } from 'folktale/maybe';
4
4
5import * as need from 'lib/need';
5import * as need from 'lib/need';
@@ -11,6 +11,7 @@ import { usePointCursor } from 'store/pointCursor';
11import View from 'components/View';
11import View from 'components/View';
12import Tabs from 'components/Tabs';
12import Tabs from 'components/Tabs';
13import Crumbs from 'components/Crumbs';
13import Crumbs from 'components/Crumbs';
14+import CopiableAddress from 'components/CopiableAddress';
14
15
15import Active from 'views/Release/Active';
16import Active from 'views/Release/Active';
16import Locked from 'views/Release/Locked';
17import Locked from 'views/Release/Locked';
@@ -45,14 +46,18 @@ export default function ReleaseView() {
45 // inputs
46 // inputs
46 const [currentTab, setCurrentTab] = useState(NAMES.ACTIVE);
47 const [currentTab, setCurrentTab] = useState(NAMES.ACTIVE);
47
48
49+ const goActive = useCallback(() => {
50+ setCurrentTab(NAMES.ACTIVE);
51+ }, [setCurrentTab]);
52+
48 const address = need.addressFromWallet(wallet);
53 const address = need.addressFromWallet(wallet);
49
54
50 return (
55 return (
51 <View pop={pop} inset>
56 <View pop={pop} inset>
52 <Grid>
57 <Grid>
53 <Grid.Item full as={Crumbs} />
58 <Grid.Item full as={Crumbs} />
54− <Grid.Item full as={H4} className="mt4">
59+ <Grid.Item full as={H1} className="f6 mono gray4 us-none pointer">
55− {address}
60+ <CopiableAddress text={address}>{address}</CopiableAddress>
56 </Grid.Item>
61 </Grid.Item>
57
62
58 <Grid.Item
63 <Grid.Item
@@ -66,6 +71,7 @@ export default function ReleaseView() {
66 onTabChange={setCurrentTab}
71 onTabChange={setCurrentTab}
67 // Tab extra
72 // Tab extra
68 goPoint={goPoint}
73 goPoint={goPoint}
74+ goActive={goActive}
69 //
75 //
70 //
76 //
71 />
77 />
src/views/Release/Active.js+11−4
@@ -10,11 +10,13 @@ import { useWallet } from 'store/wallet';
10
10
11import * as need from 'lib/need';
11import * as need from 'lib/need';
12import usePermissionsForPoint from 'lib/usePermissionsForPoint';
12import usePermissionsForPoint from 'lib/usePermissionsForPoint';
13+import { useSyncOwnedPoints } from 'lib/useSyncPoints';
13import { buildKeyType } from 'lib/point';
14import { buildKeyType } from 'lib/point';
14
15
15function ActiveViewRow({ point, goPoint }) {
16function ActiveViewRow({ point, goPoint }) {
16 const { wallet } = useWallet();
17 const { wallet } = useWallet();
17 const address = need.addressFromWallet(wallet);
18 const address = need.addressFromWallet(wallet);
19+ useSyncOwnedPoints([point]);
18 const permissions = usePermissionsForPoint(address, point);
20 const permissions = usePermissionsForPoint(address, point);
19
21
20 const keyType = buildKeyType(permissions);
22 const keyType = buildKeyType(permissions);
@@ -37,13 +39,13 @@ function ActiveViewRow({ point, goPoint }) {
37 <Sigil patp={patp} size={25} colors={['#FFFFFF', '#000000']} />
39 <Sigil patp={patp} size={25} colors={['#FFFFFF', '#000000']} />
38 </div>
40 </div>
39 </Grid.Item>
41 </Grid.Item>
40− <Grid.Item className="flex-center" cols={[6, 10]}>
42+ <Grid.Item className="flex-row align-center" cols={[6, 10]}>
41 {keyType}
43 {keyType}
42 </Grid.Item>
44 </Grid.Item>
43 <Grid.Item
45 <Grid.Item
44 onClick={onClick}
46 onClick={onClick}
45 cols={[10, 13]}
47 cols={[10, 13]}
46− className="flex-row-r align-center">
48+ className="flex-row-r align-center mr2">
47 ->
49 ->
48 </Grid.Item>
50 </Grid.Item>
49 <Grid.Divider />
51 <Grid.Divider />
@@ -76,13 +78,18 @@ export default function ActiveView({ className, goPoint }) {
76
78
77 return (
79 return (
78 <Grid full className={cn('f5', className)}>
80 <Grid full className={cn('f5', className)}>
79− <Grid.Item cols={[1, 6]} third={1}>
81+ <Grid.Item className="pv3 " cols={[1, 6]} third={1}>
80 Point
82 Point
81 </Grid.Item>
83 </Grid.Item>
82− <Grid.Item className="flex-center" cols={[6, 10]}>
84+ <Grid.Item className="pv3 " cols={[6, 10]}>
83 Key Type
85 Key Type
84 </Grid.Item>
86 </Grid.Item>
85 <Grid.Divider />
87 <Grid.Divider />
88+ {points.length === 0 && (
89+ <Grid.Item full className="flex-center pv8 f5 gray4">
90+ You have no active stars
91+ </Grid.Item>
92+ )}
86 {points.map(point => (
93 {points.map(point => (
87 <ActiveViewRow
94 <ActiveViewRow
88 key={point}
95 key={point}
src/views/Release/Locked.js+92−56
@@ -1,6 +1,7 @@
1import React, { useCallback, useEffect, useMemo } from 'react';
1import React, { useCallback, useEffect, useMemo } from 'react';
2import cn from 'classnames';
2import cn from 'classnames';
3import { Grid, Flex } from 'indigo-react';
3import { Grid, Flex } from 'indigo-react';
4+import { Just } from 'folktale/maybe';
4
5
5import * as need from 'lib/need';
6import * as need from 'lib/need';
6import useEthereumTransaction from 'lib/useEthereumTransaction';
7import useEthereumTransaction from 'lib/useEthereumTransaction';
@@ -11,6 +12,7 @@ import { usePointCache } from 'store/pointCache';
11import { useStarReleaseCache } from 'store/starRelease';
12import { useStarReleaseCache } from 'store/starRelease';
12
13
13import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
14import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
15+import { matchBlinky } from 'components/Blinky';
14
16
15import { NumberInput, AddressInput } from 'form/Inputs';
17import { NumberInput, AddressInput } from 'form/Inputs';
16import BridgeForm from 'form/BridgeForm';
18import BridgeForm from 'form/BridgeForm';
@@ -18,6 +20,24 @@ import FormError from 'form/FormError';
18import { composeValidator, buildNumberValidator } from 'form/validators';
20import { composeValidator, buildNumberValidator } from 'form/validators';
19import { convertToNumber } from 'form/formatters';
21import { convertToNumber } from 'form/formatters';
20
22
23+function MatchPluralizeStars({ quantity }) {
24+ const _quantity = quantity.getOrElse(0);
25+ console.log(quantity);
26+ return (
27+ <>
28+ {' '}
29+ <span
30+ className={cn({
31+ green2: _quantity > 0,
32+ red4: Just.hasInstance(quantity) && _quantity === 0,
33+ })}>
34+ {matchBlinky(quantity)}
35+ </span>
36+ {pluralize(_quantity, ' star ', ' stars ')}
37+ </>
38+ );
39+}
40+
21function AddressIndicator({ isOwn, className }) {
41function AddressIndicator({ isOwn, className }) {
22 return isOwn ? (
42 return isOwn ? (
23 <div className={cn('green2', className)}>✓ Current Address</div>
43 <div className={cn('green2', className)}>✓ Current Address</div>
@@ -31,7 +51,7 @@ function useWithdrawStars() {
31
51
32 const { syncStarReleaseDetails, withdraw } = useStarReleaseCache();
52 const { syncStarReleaseDetails, withdraw } = useStarReleaseCache();
33 return useEthereumTransaction(
53 return useEthereumTransaction(
34− useCallback((to, amount) => withdraw(amount, to)),
54+ useCallback((to, amount) => withdraw(amount, to), [withdraw]),
35 useCallback(
55 useCallback(
36 () => Promise.all([syncControlledPoints(), syncStarReleaseDetails()]),
56 () => Promise.all([syncControlledPoints(), syncStarReleaseDetails()]),
37 [syncStarReleaseDetails, syncControlledPoints]
57 [syncStarReleaseDetails, syncControlledPoints]
@@ -39,10 +59,17 @@ function useWithdrawStars() {
39 );
59 );
40}
60}
41
61
42−export default function LockedView({ className }) {
62+export default function Locked({ className, goActive }) {
43 const { wallet } = useWallet();
63 const { wallet } = useWallet();
44 const address = need.addressFromWallet(wallet);
64 const address = need.addressFromWallet(wallet);
65+ const {
66+ bind,
67+ construct,
68+ unconstruct,
69+ inputsLocked,
70+ completed,
71+ reset,
45− const { bind, construct, unconstruct, inputsLocked } = useWithdrawStars();
72+ } = useWithdrawStars();
46
73
47 const { syncStarReleaseDetails, starReleaseDetails } = useStarReleaseCache();
74 const { syncStarReleaseDetails, starReleaseDetails } = useStarReleaseCache();
48
75
@@ -61,79 +88,88 @@ export default function LockedView({ className }) {
61 [construct, unconstruct]
88 [construct, unconstruct]
62 );
89 );
63
90
64− const available = starReleaseDetails
65− .map(b => b.available - b.withdrawn)
91+ const canWithdraw = starReleaseDetails.map(b => b.available - b.withdrawn);
66− .getOrElse(0);
67− const total = starReleaseDetails.map(b => b.total).getOrElse(0);
92+ const total = starReleaseDetails.map(b => b.total);
68− const withdrawn = starReleaseDetails.map(b => b.withdrawn).getOrElse(0);
69
93
70 const validate = useMemo(
94 const validate = useMemo(
71 () =>
95 () =>
72− composeValidator({
96+ composeValidator(
97+ {
73− numStars: buildNumberValidator(0, available + 1),
98+ numStars: buildNumberValidator(0, canWithdraw + 1),
99+ },
100+ (values, errors) => (inputsLocked ? false : errors)
74− }),
101+ ),
75− [available]
102+ [canWithdraw, inputsLocked]
76 );
103 );
77
104
78 const initialValues = { address };
105 const initialValues = { address };
79
106
80 return (
107 return (
81− <Grid gap={6} className={cn('mt4', className)} full>
108+ <Grid gap={completed ? 0 : 6} className={cn('mt4', className)} full>
82 <BridgeForm
109 <BridgeForm
83 initialValues={initialValues}
110 initialValues={initialValues}
84 onValues={onValues}
111 onValues={onValues}
85 validate={validate}>
112 validate={validate}>
86− {({ values, reset }) => (
113+ {({ values, form }) => (
87 <>
114 <>
115+ {!completed && (
116+ <>
88− <Grid.Item full className="f5">
117+ <Grid.Item full className="f5">
89− You have{' '}
118+ You have <MatchPluralizeStars quantity={canWithdraw} />
90− <span
91− className={cn({
92− green2: available > 0,
93− red4: available === 0,
94− })}>
95− {available}
96− </span>
97− {pluralize(available, ' star ', ' stars ')}
98− available to withdraw
119+ available to withdraw
99− <br />
120+ <br />
100− You have <span className="green2">{total - withdrawn}</span>
121+ You have
101− {pluralize(available, ' star ', ' stars ')}
122+ <MatchPluralizeStars quantity={total} />
102− total
123+ total
103− </Grid.Item>
124+ </Grid.Item>
125+ <Grid.Item
126+ cols={[1, 4]}
127+ label="Stars"
128+ as={NumberInput}
129+ placeholder="#"
130+ name="numStars"
131+ disabled={inputsLocked}
132+ accessory={
133+ <div className="flex-center h-full">
134+ / &nbsp;{matchBlinky(canWithdraw)}
135+ </div>
136+ }
137+ />
104− <Grid.Item full className="f5" cols={[1, 10]} as={Flex} col>
138+ <Grid.Item full className="f5" cols={[1, 13]} as={Flex} col>
105− <Flex.Item
139+ <Flex.Item
106− name="address"
140+ name="address"
107− as={AddressInput}
141+ as={AddressInput}
108− label="Withdraw To"
142+ label="Withdraw To"
109− disabled={inputsLocked}
143+ disabled={inputsLocked}
110− />
144+ />
111− <Flex.Item
145+ <Flex.Item
112− as={AddressIndicator}
146+ as={AddressIndicator}
113− isOwn={address === values.address}
147+ isOwn={address === values.address}
114− />
148+ />
115− </Grid.Item>
149+ </Grid.Item>
150+ </>
151+ )}
116
152
117− <Grid.Item
118− cols={[1, 5]}
119− label="Stars"
120− style={{ minWidth: '0' }}
121− as={NumberInput}
122− placeholder="#"
123− name="numStars"
124− disabled={inputsLocked}
125− />
126− <Grid.Item as={Flex} col cols={[5, 8]}>
127− <Flex.Item className="f6 lh-tall">&nbsp;</Flex.Item>
128− <Flex.Item className="f3">/ {available}</Flex.Item>
129− </Grid.Item>
130 <Grid.Item full as={FormError} />
153 <Grid.Item full as={FormError} />
154+ {completed && (
155+ <>
156+ <Grid.Item full className="pv4">
157+ {values.numStars}{' '}
158+ {pluralize(values.numStars, 'star has', 'stars have')} been
159+ withdrawn
160+ </Grid.Item>
161+ <Grid.Divider />
162+ </>
163+ )}
131 <Grid.Item
164 <Grid.Item
132 full
165 full
133 as={InlineEthereumTransaction}
166 as={InlineEthereumTransaction}
134 {...bind}
167 {...bind}
135− onReturn={() => reset()}
136 label="Withdraw Stars"
168 label="Withdraw Stars"
169+ onReturn={() => {
170+ reset();
171+ form.reset();
172+ }}
137 />
173 />
138 </>
174 </>
139 )}
175 )}