import React, { createContext, forwardRef, useCallback, useContext, useState, } from 'react'; import Maybe from 'folktale/maybe'; import * as azimuth from 'azimuth-js'; import { useNetwork } from './network'; export const PointCacheContext = createContext(null); // the default value of a point's invites const kEmptyInvites = { availableInvites: Maybe.Nothing(), sentInvites: Maybe.Nothing(), acceptedInvites: Maybe.Nothing(), }; function _usePointCache() { const { contracts, web3 } = useNetwork(); const [pointCache, _setPointCache] = useState({}); const [birthdayCache, _setBirthdayCache] = useState({}); const [invitesCache, _setInvitesCache] = useState({}); const addToPointCache = useCallback( entry => _setPointCache(cache => ({ ...cache, ...entry })), [_setPointCache] ); const addToBirthdayCache = useCallback( entry => _setBirthdayCache(cache => ({ ...cache, ...entry })), [_setBirthdayCache] ); const addToInvitesCache = useCallback( entry => _setInvitesCache(cache => ({ ...cache, ...entry })), [_setInvitesCache] ); // TODO: refactor pointCache access to use accessor like bithday const getBirthday = useCallback( point => birthdayCache[point] || Maybe.Nothing(), [birthdayCache] ); const getInvites = useCallback( point => invitesCache[point] || kEmptyInvites, [invitesCache] ); const fetchPoint = useCallback( async point => { const _contracts = contracts.getOrElse(null); const _web3 = web3.getOrElse(null); if (!_contracts || !_web3) { return; } // fetch point details const details = await azimuth.azimuth.getPoint(_contracts, point); addToPointCache({ [point]: details }); // fetch invites const count = await azimuth.delegatedSending.getTotalUsableInvites( _contracts, point ); addToInvitesCache({ [point]: { availableInvites: Maybe.Just(count), // TODO: look up sent/accepted on-chain sentInvites: Maybe.Just(6), acceptedInvites: Maybe.Just(5), }, }); // fetch birthday (if not already known — will not change after being set) if (Maybe.Nothing.hasInstance(getBirthday(point))) { const birthBlock = await azimuth.azimuth.getActivationBlock( _contracts, point ); if (birthBlock > 0) { const block = await _web3.eth.getBlock(birthBlock); addToBirthdayCache({ [point]: Maybe.Just(new Date(block.timestamp * 1000)), }); } } }, [ contracts, web3, addToPointCache, addToBirthdayCache, getBirthday, addToInvitesCache, ] ); return { pointCache, getBirthday, getInvites, addToPointCache, fetchPoint, }; } export function PointCacheProvider({ children }) { const pointCache = _usePointCache(); return ( {children} ); } // Hook version export function usePointCache() { return useContext(PointCacheContext); } // HOC version export const withPointCache = Component => forwardRef((props, ref) => ( {pointCache => } ));