@@ -0,0 +1,179 @@
1+import React, { useCallback, useEffect, useMemo } from 'react';
2+import cn from 'classnames';
3+import { Grid, Flex } from 'indigo-react';
4+import { Just } from 'folktale/maybe';
5+
6+import * as need from 'lib/need';
7+import useEthereumTransaction from 'lib/useEthereumTransaction';
8+import pluralize from 'lib/pluralize';
9+
10+import { useWallet } from 'store/wallet';
11+import { usePointCache } from 'store/pointCache';
12+import { useStarReleaseCache } from 'store/starRelease';
13+
14+import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
15+import { matchBlinky } from 'components/Blinky';
16+
17+import { NumberInput, AddressInput } from 'form/Inputs';
18+import BridgeForm from 'form/BridgeForm';
19+import FormError from 'form/FormError';
20+import { composeValidator, buildNumberValidator } from 'form/validators';
21+import { convertToNumber } from 'form/formatters';
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+
41+function AddressIndicator({ isOwn, className }) {
42+ return isOwn ? (
43+ <div className={cn('green2', className)}>✓ Current Address</div>
44+ ) : (
45+ <div className={cn('red4', className)}>! Different address</div>
46+ );
47+}
48+
49+function useWithdrawStars() {
50+ const { syncControlledPoints } = usePointCache();
51+
52+ const { syncStarReleaseDetails, withdraw } = useStarReleaseCache();
53+ return useEthereumTransaction(
54+ useCallback((to, amount) => withdraw(amount, to), [withdraw]),
55+ useCallback(
56+ () => Promise.all([syncControlledPoints(), syncStarReleaseDetails()]),
57+ [syncStarReleaseDetails, syncControlledPoints]
58+ )
59+ );
60+}
61+
62+export default function Locked({ className, goActive }) {
63+ const { wallet } = useWallet();
64+ const address = need.addressFromWallet(wallet);
65+ const {
66+ bind,
67+ construct,
68+ unconstruct,
69+ inputsLocked,
70+ completed,
71+ reset,
72+ } = useWithdrawStars();
73+
74+ const { syncStarReleaseDetails, starReleaseDetails } = useStarReleaseCache();
75+
76+ useEffect(() => {
77+ syncStarReleaseDetails();
78+ }, [syncStarReleaseDetails]);
79+
80+ const onValues = useCallback(
81+ ({ valid, values }) => {
82+ if (valid) {
83+ construct(values.address, convertToNumber(values.numStars));
84+ } else {
85+ unconstruct();
86+ }
87+ },
88+ [construct, unconstruct]
89+ );
90+
91+ const canWithdraw = starReleaseDetails.map(b => b.available - b.withdrawn);
92+ const total = starReleaseDetails.map(b => b.total);
93+
94+ const validate = useMemo(
95+ () =>
96+ composeValidator(
97+ {
98+ numStars: buildNumberValidator(0, canWithdraw + 1),
99+ },
100+ (values, errors) => (inputsLocked ? false : errors)
101+ ),
102+ [canWithdraw, inputsLocked]
103+ );
104+
105+ const initialValues = { address };
106+
107+ return (
108+ <Grid gap={completed ? 0 : 6} className={cn('mt4', className)} full>
109+ <BridgeForm
110+ initialValues={initialValues}
111+ onValues={onValues}
112+ validate={validate}>
113+ {({ values, form }) => (
114+ <>
115+ {!completed && (
116+ <>
117+ <Grid.Item full className="f5">
118+ You have <MatchPluralizeStars quantity={canWithdraw} />
119+ available to withdraw
120+ <br />
121+ You have
122+ <MatchPluralizeStars quantity={total} />
123+ total
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+ / {matchBlinky(canWithdraw)}
135+ </div>
136+ }
137+ />
138+ <Grid.Item full className="f5" cols={[1, 13]} as={Flex} col>
139+ <Flex.Item
140+ name="address"
141+ as={AddressInput}
142+ label="Withdraw To"
143+ disabled={inputsLocked}
144+ />
145+ <Flex.Item
146+ as={AddressIndicator}
147+ isOwn={address === values.address}
148+ />
149+ </Grid.Item>
150+ </>
151+ )}
152+
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+ )}
164+ <Grid.Item
165+ full
166+ as={InlineEthereumTransaction}
167+ {...bind}
168+ label="Withdraw Stars"
169+ onReturn={() => {
170+ reset();
171+ form.reset();
172+ }}
173+ />
174+ </>
175+ )}
176+ </BridgeForm>
177+ </Grid>
178+ );
179+}