on master help sign in
chore: various refactors, cleanups, comments for review
commitda9b631553879ed71a3193bca22d274dceb91d14 authorMatt Condon (shrugs) <mattgcondon@gmail.com> dateWed 26 Jun 2019, 16:53 (7 years ago) parent1119b52
11 files changed+93−89
src/components/LoadableButton.js+1 src/components/MiniBackButton.js+1−1 src/indigo-react/components/Button.js+1−1 src/indigo-react/lib/useForm.js+21−19 src/lib/useSyncPoints.js+17−2 src/store/lib/useBirthdaysStore.js+15−13 src/store/lib/useControlledPointsStore.js+13−20 src/store/lib/useInvitesStore.js+11−21 src/store/lib/usePointStore.js+8−6 src/views/Login.js+4−5 src/views/ViewPoint.js+1−1
src/components/LoadableButton.js+1
@@ -1,6 +1,7 @@
11import React from 'react';
22import { Button } from 'indigo-react';
33
4+// TODO: implement loading bar behind text
45export default function LoadableButton({ ...rest }) {
56 return <Button {...rest}></Button>;
67}
src/components/MiniBackButton.js+1−1
@@ -1,8 +1,8 @@
11import React from 'react';
22import cn from 'classnames';
3+import { IconButton } from 'indigo-react';
34
45import { ReactComponent as Back } from 'assets/back.svg';
5−import { IconButton } from 'indigo-react';
66
77export default ({ className, ...rest }) => (
88 <IconButton {...rest}>
src/indigo-react/components/Button.js+1−1
@@ -45,7 +45,7 @@ export default function Button({
4545 cursor: 'not-allowed',
4646 }),
4747 }}
48− onClick={onClick ? () => !disabled && onClick() : undefined}
48+ onClick={!disabled && onClick ? onClick : undefined}
4949 {...rest}>
5050 <Grid.Item as={Flex} justify="between" full>
5151 <span className={cn(textColor)}>{children}</span>
src/indigo-react/lib/useForm.js+21−19
@@ -3,6 +3,7 @@ import { keyBy, get, every, some } from 'lodash';
33
44import { compose } from 'lib/lib';
55import { kDefaultValidator } from 'lib/validators';
6+import useSetState from 'lib/useSetState';
67
78// interface InputConfig {
89// name: string;
@@ -21,7 +22,7 @@ const defaultsFor = (configs, mapper) =>
2122 );
2223
2324/**
24− * useForm managest a set of inputs for rendering them in a loop
25+ * useForm manages a set of inputs for rendering them in a loop
2526 */
2627export default function useForm(configs = []) {
2728 const byName = useMemo(() => keyBy(configs, 'name'), [configs]);
@@ -42,7 +43,7 @@ export default function useForm(configs = []) {
4243 // until there's a traditional state update.
4344
4445 // track focused states
45− const [focused, _setFocused] = useState(() =>
46+ const [focused, setFocused] = useSetState(() =>
4647 defaultsFor(configs, config => config.autoFocus && !config.disabled)
4748 );
4849 const focuses = useMemo(
@@ -50,23 +51,16 @@ export default function useForm(configs = []) {
5051 [configs, focused]
5152 );
5253
53− const setFocused = useCallback(
54− (name, value) => _setFocused(values => ({ ...values, [name]: value })),
55− [_setFocused]
56− );
57−
5854 // track whether or not input has been focused
59− const [hasBeenFocused, _setHasBeenFocused] = useState({});
60− const setHasBeenFocused = useCallback(
61− (name, value) =>
62− _setHasBeenFocused(values => ({ ...values, [name]: value })),
63− [_setHasBeenFocused]
64− );
55+ const [hasBeenFocused, setHasBeenFocused] = useSetState({});
6556
57+ // build fn that transforms a value by input name
6658 const transform = useCallback(
6759 (name, value) => compose(...get(byName, [name, 'transformers'], []))(value),
6860 [byName]
6961 );
62+
63+ // build fn that validates a value by input name
7064 const validate = useCallback(
7165 (name, value) =>
7266 compose(
@@ -76,28 +70,33 @@ export default function useForm(configs = []) {
7670 [byName]
7771 );
7872
73+ // on change, transform and set value
7974 const onChange = useCallback(
8075 name => e => setValue(name, transform(name, e.target.value)), //
8176 [setValue, transform]
8277 );
78+ // on focus, update focus
8379 const onFocus = useCallback(
84− name => e => setFocused(name, true), //
80+ name => e => setFocused({ [name]: true }), //
8581 [setFocused]
8682 );
83+
84+ // on blur, defocus and set has been focused
8785 const onBlur = useCallback(
8886 name => e => {
89− setFocused(name, false);
90− setHasBeenFocused(name, true);
87+ setFocused({ [name]: false });
88+ setHasBeenFocused({ [name]: false });
9189 },
9290 [setFocused, setHasBeenFocused]
9391 );
9492
95− // memo-compute whether or not the current value is valid
93+ // memo-compute validations of curent values
9694 const validations = useMemo(
9795 () => configs.map(config => validate(config.name, values[config.name])), //
9896 [configs, validate, values]
9997 );
10098
99+ // memo-compute the set of (perhaps changed by validation) data
101100 const datas = useMemo(() => validations.map(v => v.data), [validations]);
102101
103102 // the input has errored if it
@@ -137,6 +136,7 @@ export default function useForm(configs = []) {
137136 [configs, hasBeenFocused, focused, passes]
138137 );
139138
139+ // generate the list of input states
140140 const inputs = useMemo(
141141 () =>
142142 configs.map(
@@ -175,8 +175,10 @@ export default function useForm(configs = []) {
175175 ]
176176 );
177177
178− const pass = every(passes);
179− const error = some(errors);
178+ // did all of the inputs pass validation?
179+ const pass = useMemo(() => every(passes), [passes]);
180+ // did any of the inputs error?
181+ const error = useMemo(() => some(errors), [errors]);
180182
181183 return {
182184 inputs,
src/lib/useSyncPoints.js+17−2
@@ -4,9 +4,24 @@ import { isEqual } from 'lodash';
44import { usePointCache } from 'store/pointCache';
55import usePreviousValue from 'lib/usePreviousValue';
66
7−// sync a known point to the cache (i.e display values)
7+// sync a known (i.e. mine) point to the cache (i.e display values)
88export function useSyncKnownPoints(points = []) {
9− //
9+ // TBD: right now we don't need anything more than the point itself
10+ // but soon we'll need to know information around "key type"
11+}
12+
13+// sync a foreign (not the user's) point to the cache
14+export function useSyncForeignPoints(points = []) {
15+ const { syncForeignPoint } = usePointCache();
16+ const prevPoints = usePreviousValue(points);
17+
18+ useEffect(() => {
19+ if (!isEqual(prevPoints, points)) {
20+ // if the actual set of points changes, sync the whole array
21+ // TODO: we should get clever about caching
22+ points.forEach(point => syncForeignPoint(point));
23+ }
24+ }, [syncForeignPoint, prevPoints, points]);
1025}
1126
1227// sync an owned point to the cache
src/store/lib/useBirthdaysStore.js+15−13
@@ -30,19 +30,21 @@ export default function useBirthdayStore() {
3030 return;
3131 }
3232
33− // fetch birthday if not already known—will not change after being set
34− if (Maybe.Nothing.hasInstance(getBirthday(point))) {
35− const birthBlock = await azimuth.azimuth.getActivationBlock(
36− _contracts,
37− point
38− );
39−
40− if (birthBlock > 0) {
41− const block = await _web3.eth.getBlock(birthBlock);
42− addToBirthdayCache({
43− [point]: Maybe.Just(new Date(block.timestamp * 1000)),
44− });
45− }
33+ // birthday will not change after being set, so bail if we already know
34+ if (Maybe.Just.hasInstance(getBirthday(point))) {
35+ return;
36+ }
37+
38+ const birthBlock = await azimuth.azimuth.getActivationBlock(
39+ _contracts,
40+ point
41+ );
42+
43+ if (birthBlock > 0) {
44+ const block = await _web3.eth.getBlock(birthBlock);
45+ addToBirthdayCache({
46+ [point]: Maybe.Just(new Date(block.timestamp * 1000)),
47+ });
4648 }
4749 },
4850 [contracts, web3, addToBirthdayCache, getBirthday]
src/store/lib/useControlledPointsStore.js+13−20
@@ -34,26 +34,19 @@ export default function useControlledPointsStore() {
3434
3535 const address = _wallet.address;
3636
37− const ownedPoints = await azimuth.azimuth.getOwnedPoints(
38− _contracts,
39− address
40− );
41− const incomingPoints = await azimuth.azimuth.getTransferringFor(
42− _contracts,
43− address
44− );
45− const managingPoints = await azimuth.azimuth.getManagerFor(
46− _contracts,
47− address
48− );
49− const votingPoints = await azimuth.azimuth.getVotingFor(
50− _contracts,
51− address
52− );
53− const spawningPoints = await azimuth.azimuth.getSpawningFor(
54− _contracts,
55− address
56− );
37+ const [
38+ ownedPoints,
39+ incomingPoints,
40+ managingPoints,
41+ votingPoints,
42+ spawningPoints,
43+ ] = await Promise.all([
44+ azimuth.azimuth.getOwnedPoints(_contracts, address),
45+ azimuth.azimuth.getTransferringFor(_contracts, address),
46+ azimuth.azimuth.getManagerFor(_contracts, address),
47+ azimuth.azimuth.getVotingFor(_contracts, address),
48+ azimuth.azimuth.getSpawningFor(_contracts, address),
49+ ]);
5750
5851 _setControlledPointsCache({
5952 ownedPoints: Maybe.Just(ownedPoints),
src/store/lib/useInvitesStore.js+11−21
@@ -36,29 +36,19 @@ export default function useInvitesStore() {
3636 return;
3737 }
3838
39− const availableInvites = await azimuth.delegatedSending.getTotalUsableInvites(
40− _contracts,
41− point
42− );
39+ const [availableInvites, invitedPoints] = await Promise.all([
40+ azimuth.delegatedSending.getTotalUsableInvites(_contracts, point),
41+ azimuth.delegatedSending.getInvited(_contracts, point),
42+ ]);
4343
44− const invitedPoints = await azimuth.delegatedSending.getInvited(
45− _contracts,
46− point
47− );
48− const invitedPointDetails = await Promise.all(
49− invitedPoints.map(async invitedPoint => {
50− const active = await azimuth.azimuth.isActive(
51− _contracts,
52− invitedPoint
53− );
54− return {
55− point: invitedPoint,
56− active,
57− };
58− })
44+ const activity = await Promise.all(
45+ invitedPoints.map(invitedPoint =>
46+ azimuth.azimuth.isActive(_contracts, invitedPoint)
47+ )
5948 );
60− const sentInvites = invitedPointDetails.length;
61− const acceptedInvites = invitedPointDetails.filter(i => i.active).length;
49+
50+ const sentInvites = invitedPoints.length;
51+ const acceptedInvites = activity.filter(i => i.active).length;
6252
6353 addToInvitesCache({
6454 [point]: {
src/store/lib/usePointStore.js+8−6
@@ -15,15 +15,17 @@ export default function usePointStore() {
1515 } = useControlledPointsStore();
1616
1717 // sync all of the on-chain info required to display a foreign point
18− const syncForeignPoint = useCallback(
19− async point => Promise.all([syncDetails(point), syncBirthday(point)]),
20− [syncDetails, syncBirthday]
21− );
18+ const syncForeignPoint = useCallback(async point => Promise.all([]), []);
2219
2320 // sync all of the on-chain info required for a point that the user owns
2421 const syncOwnedPoint = useCallback(
25− async point => Promise.all([syncForeignPoint(point), syncInvites(point)]),
26− [syncForeignPoint, syncInvites]
22+ async point =>
23+ Promise.all([
24+ syncDetails(point),
25+ syncBirthday(point),
26+ syncInvites(point),
27+ ]),
28+ [syncDetails, syncBirthday, syncInvites]
2729 );
2830
2931 return {
src/views/Login.js+4−5
@@ -57,8 +57,8 @@ export default function Login() {
5757 const _contracts = need.contracts(contracts);
5858
5959 // if no point cursor set by login logic, try to deduce it
60− let deduced = Nothing();
61− if (Nothing.hasInstance(pointCursor)) {
60+ let deduced = pointCursor;
61+ if (Nothing.hasInstance(deduced)) {
6262 const owned = await azimuth.azimuth.getOwnedPoints(
6363 _contracts,
6464 _wallet.address
@@ -80,9 +80,8 @@ export default function Login() {
8080 // navigate to that specific point, otherwise navigate to list of points
8181 if (Just.hasInstance(deduced)) {
8282 setPointCursor(deduced);
83− history.popAndPush(ROUTE_NAMES.POINT);
84− } else if (Just.hasInstance(pointCursor)) {
85− history.popAndPush(ROUTE_NAMES.POINT);
83+ history.popAndPush(ROUTE_NAMES.POINTS);
84+ history.push(ROUTE_NAMES.POINT);
8685 } else {
8786 history.popAndPush(ROUTE_NAMES.POINTS);
8887 }
src/views/ViewPoint.js+1−1
@@ -1,4 +1,4 @@
1−import React, { useCallback, useState } from 'react';
1+import React, { useCallback } from 'react';
22import Maybe from 'folktale/maybe';
33import * as ob from 'urbit-ob';
44import { Input } from 'indigo-react';