Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: separate approve and perform buttons #257

Merged
merged 3 commits into from
Oct 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import * as React from "react";
import Button from "react-bootstrap/Button";
import Spinner from "react-bootstrap/Spinner";
import Image from "react-bootstrap/Image";
import { BigNumber, constants } from "ethers";
import { SidebarProps } from "./Sidebar";
import { PAYMENT_TOKEN } from "../lib/constants";

export type ApproveOrPerformButtonProps = SidebarProps & {
export type ApproveButtonProps = SidebarProps & {
isDisabled: boolean;
performAction: () => Promise<string | void>;
buttonText: string;
requiredPayment: BigNumber | null;
requiredFlowAmount: BigNumber | null;
requiredFlowPermissions: number | null;
Expand All @@ -17,6 +16,8 @@ export type ApproveOrPerformButtonProps = SidebarProps & {
setErrorMessage: (v: string) => void;
setIsActing: (v: boolean) => void;
setDidFail: (v: boolean) => void;
isAllowed: boolean;
setIsAllowed: React.Dispatch<React.SetStateAction<boolean>>;
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -27,11 +28,9 @@ const asyncEvery = async (arr: any, predicate: any) => {
return true;
};

export function ApproveOrPerformButton(props: ApproveOrPerformButtonProps) {
export function ApproveButton(props: ApproveButtonProps) {
const {
isDisabled,
performAction,
buttonText,
paymentToken,
account,
spender,
Expand All @@ -44,12 +43,14 @@ export function ApproveOrPerformButton(props: ApproveOrPerformButtonProps) {
setErrorMessage,
setIsActing,
setDidFail,
isAllowed,
setIsAllowed,
} = props;

const [approvals, setApprovals] = React.useState<(() => Promise<boolean>)[]>(
[]
);
const [approvalStr, setApprovalStr] = React.useState<string>(buttonText);
const [approvalStr, setApprovalStr] = React.useState<string>("");
const [completedActions, setCompletedActions] = React.useState<number>(0);
const [totalActions, setTotalActions] = React.useState<number>(0);

Expand Down Expand Up @@ -132,7 +133,7 @@ export function ApproveOrPerformButton(props: ApproveOrPerformButtonProps) {
React.useEffect(() => {
const checkRequirements = async () => {
const _approvals: (() => Promise<boolean>)[] = [];
let _approvalStr = buttonText;
let _approvalStr = `Allow ${PAYMENT_TOKEN} Transfer`;

if (!isReady) {
setApprovals(_approvals);
Expand Down Expand Up @@ -175,6 +176,12 @@ export function ApproveOrPerformButton(props: ApproveOrPerformButtonProps) {
: `Allow ${PAYMENT_TOKEN} Stream`;
}

if (_approvals.length === 0) {
setIsAllowed(true);
} else {
setIsAllowed(false);
}

setApprovals(_approvals);
setApprovalStr(_approvalStr);
};
Expand All @@ -194,30 +201,38 @@ export function ApproveOrPerformButton(props: ApproveOrPerformButtonProps) {
if (approvals.length > 0) {
setTotalActions(approvals.length);
setCompletedActions(0);
setApprovalStr(buttonText);
let _completedActions = 0;
await asyncEvery(approvals, async (f: () => Promise<boolean>) => {
const success = await f();
setCompletedActions(++_completedActions);
return success;
});
} else {
setTotalActions(1);
setCompletedActions(0);
const isSubmissionSuccessful = await asyncEvery(
approvals,
async (f: () => Promise<boolean>) => {
const success = await f();
setCompletedActions(++_completedActions);
return success;
}
);

await performAction();
setTotalActions(0);
if (!isSubmissionSuccessful) {
setCompletedActions(0);
setTotalActions(0);
}
}
}, [approvals, completedActions, buttonText]);
}, [approvals, completedActions]);

return (
<Button
variant="primary"
className="w-100"
variant={isAllowed ? "info" : "primary"}
className="w-100 mb-3"
onClick={() => submit()}
disabled={isDisabled || totalActions > completedActions || !isReady}
disabled={
isDisabled || !isReady || isAllowed || totalActions > completedActions
}
>
{totalActions > completedActions ? (
{isAllowed ? (
<>
<span className="ms-4">{PAYMENT_TOKEN} use allowed</span>
<Image src="./task-done.svg" className="float-end"></Image>
</>
) : totalActions > completedActions ? (
<>
{spinner} {`${completedActions}/${totalActions}`}
</>
Expand All @@ -228,4 +243,4 @@ export function ApproveOrPerformButton(props: ApproveOrPerformButtonProps) {
);
}

export default ApproveOrPerformButton;
export default ApproveButton;
44 changes: 44 additions & 0 deletions components/PerformButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as React from "react";
import Button from "react-bootstrap/Button";
import Spinner from "react-bootstrap/Spinner";

export type PerformButtonProps = {
isDisabled: boolean;
isAllowed: boolean;
isActing: boolean;
performAction: () => Promise<string | void>;
buttonText: string;
};

export function PerformButton(props: PerformButtonProps) {
const { isDisabled, isAllowed, isActing, performAction, buttonText } = props;

const submit = React.useCallback(async () => {
await performAction();
}, [performAction]);

const spinner = (
<Spinner as="span" size="sm" animation="border" role="status">
<span className="visually-hidden">Sending Transaction...</span>
</Spinner>
);

return (
<Button
variant={
!isAllowed
? "info"
: buttonText === "Reject Bid"
? "danger"
: "success"
}
className="w-100"
onClick={() => submit()}
disabled={isDisabled || !isAllowed}
>
{isActing ? spinner : buttonText}
</Button>
);
}

export default PerformButton;
37 changes: 23 additions & 14 deletions components/cards/ActionForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import { model as GeoWebModel, BasicProfile } from "@geo-web/datamodels";
import { DataModel } from "@glazed/datamodel";
import { AssetContentManager } from "../../lib/AssetContentManager";
import TransactionError from "./TransactionError";
import { ApproveOrPerformButton } from "../ApproveOrPerformButton";
import ApproveButton from "../ApproveButton";
import PerformButton from "../PerformButton";

export type ActionFormProps = SidebarProps & {
perSecondFeeNumerator: BigNumber;
Expand Down Expand Up @@ -90,6 +91,7 @@ export function ActionForm(props: ActionFormProps) {
errorMessage,
} = actionData;
const [showWrapModal, setShowWrapModal] = React.useState(false);
const [isAllowed, setIsAllowed] = React.useState(false);

const handleWrapModalOpen = () => setShowWrapModal(true);
const handleWrapModalClose = () => setShowWrapModal(false);
Expand Down Expand Up @@ -377,22 +379,13 @@ export function ActionForm(props: ActionFormProps) {
className="w-100 mb-3"
onClick={handleWrapModalOpen}
>
{`Wrap to ${PAYMENT_TOKEN}`}
{`Wrap ETH to ${PAYMENT_TOKEN}`}
</Button>
<ApproveOrPerformButton
<ApproveButton
{...props}
isDisabled={isActing || isLoading || isInvalid}
buttonText={
interactionState === STATE.PARCEL_EDITING
? "Submit"
: interactionState === STATE.PARCEL_RECLAIMING &&
account.toLowerCase() === licenseOwner?.toLowerCase()
? "Reclaim"
: "Claim"
}
requiredFlowAmount={requiredFlowAmount}
isDisabled={isActing ?? false}
requiredFlowAmount={requiredFlowAmount ?? null}
requiredPayment={requiredPayment ?? null}
performAction={submit}
spender={spender ?? null}
setErrorMessage={(v) => {
updateActionData({ errorMessage: v });
Expand All @@ -403,6 +396,22 @@ export function ActionForm(props: ActionFormProps) {
setDidFail={(v) => {
updateActionData({ didFail: v });
}}
isAllowed={isAllowed}
setIsAllowed={setIsAllowed}
/>
<PerformButton
isDisabled={isActing || isLoading || isInvalid}
isActing={isActing ?? false}
buttonText={
interactionState === STATE.PARCEL_EDITING
? "Submit"
: interactionState === STATE.PARCEL_RECLAIMING &&
account.toLowerCase() === licenseOwner?.toLowerCase()
? "Reclaim"
: "Claim"
}
performAction={submit}
isAllowed={isAllowed}
/>
</Form>

Expand Down
31 changes: 21 additions & 10 deletions components/cards/PlaceBidAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import { STATE } from "../Map";
import InfoTooltip from "../InfoTooltip";
import TransactionError from "./TransactionError";
import type { PCOLicenseDiamond } from "@geo-web/contracts/dist/typechain-types/PCOLicenseDiamond";
import { ApproveOrPerformButton } from "../ApproveOrPerformButton";
import { ApproveButton } from "../ApproveButton";
import { PerformButton } from "../PerformButton";
import { GeoWebParcel } from "./ParcelInfo";

export type PlaceBidActionProps = SidebarProps & {
Expand Down Expand Up @@ -55,8 +56,10 @@ function PlaceBidAction(props: PlaceBidActionProps) {
const [didFail, setDidFail] = React.useState(false);
const [errorMessage, setErrorMessage] = React.useState("");
const [isActing, setIsActing] = React.useState(false);
const [displayNewForSalePrice, setDisplayNewForSalePrice] =
React.useState<string | null>(null);
const [displayNewForSalePrice, setDisplayNewForSalePrice] = React.useState<
string | null
>(null);
const [isAllowed, setIsAllowed] = React.useState(false);

const handleWrapModalOpen = () => setShowWrapModal(true);
const handleWrapModalClose = () => setShowWrapModal(false);
Expand Down Expand Up @@ -109,8 +112,9 @@ function PlaceBidAction(props: PlaceBidActionProps) {

const isInvalid = isForSalePriceInvalid || !displayNewForSalePrice;

const [requiredBuffer, setRequiredBuffer] =
React.useState<BigNumber | null>(null);
const [requiredBuffer, setRequiredBuffer] = React.useState<BigNumber | null>(
null
);
React.useEffect(() => {
const run = async () => {
if (!newNetworkFee) {
Expand Down Expand Up @@ -273,25 +277,32 @@ function PlaceBidAction(props: PlaceBidActionProps) {
className="w-100 mb-3"
onClick={handleWrapModalOpen}
>
{`Wrap to ${PAYMENT_TOKEN}`}
{`Wrap ETH to ${PAYMENT_TOKEN}`}
</Button>
<ApproveOrPerformButton
<ApproveButton
{...props}
isDisabled={isActing || isInvalid}
buttonText={"Place Bid"}
isDisabled={isActing}
requiredFlowAmount={annualNetworkFeeRate ?? null}
requiredPayment={
newForSalePrice && requiredBuffer
? newForSalePrice.add(requiredBuffer)
: null
}
performAction={placeBid}
spender={licenseDiamondContract?.address ?? null}
requiredFlowPermissions={1}
flowOperator={licenseDiamondContract?.address ?? null}
setErrorMessage={setErrorMessage}
setIsActing={setIsActing}
setDidFail={setDidFail}
isAllowed={isAllowed}
setIsAllowed={setIsAllowed}
/>
<PerformButton
isDisabled={isActing || isInvalid}
isActing={isActing}
buttonText={"Place Bid"}
performAction={placeBid}
isAllowed={isAllowed}
/>
</Form>

Expand Down
21 changes: 15 additions & 6 deletions components/cards/RejectBidAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import { STATE } from "../Map";
import InfoTooltip from "../InfoTooltip";
import TransactionError from "./TransactionError";
import type { PCOLicenseDiamond } from "@geo-web/contracts/dist/typechain-types/PCOLicenseDiamond";
import { ApproveOrPerformButton } from "../ApproveOrPerformButton";
import ApproveButton from "../ApproveButton";
import PerformButton from "../PerformButton";
import { GeoWebParcel } from "./ParcelInfo";

dayjs.extend(utc);
Expand Down Expand Up @@ -76,6 +77,7 @@ function RejectBidAction(props: RejectBidActionProps) {
const [isActing, setIsActing] = React.useState(false);
const [displayNewForSalePrice, setDisplayNewForSalePrice] =
React.useState<string>(bidForSalePriceDisplay);
const [isAllowed, setIsAllowed] = React.useState(false);

const handleWrapModalOpen = () => setShowWrapModal(true);
const handleWrapModalClose = () => setShowWrapModal(false);
Expand Down Expand Up @@ -376,25 +378,32 @@ function RejectBidAction(props: RejectBidActionProps) {
className="w-100 mb-3"
onClick={handleWrapModalOpen}
>
{`Wrap to ${PAYMENT_TOKEN}`}
{`Wrap ETH to ${PAYMENT_TOKEN}`}
</Button>
<ApproveOrPerformButton
<ApproveButton
{...props}
isDisabled={isActing || isInvalid}
buttonText={"Reject Bid"}
isDisabled={isActing}
requiredFlowAmount={annualNetworkFeeRate ?? null}
requiredPayment={
penaltyPayment && newRequiredBuffer && oldRequiredBuffer
? penaltyPayment.add(newRequiredBuffer).sub(oldRequiredBuffer)
: null
}
performAction={rejectBid}
spender={licenseDiamondContract?.address ?? null}
requiredFlowPermissions={2}
flowOperator={licenseDiamondContract?.address ?? null}
setErrorMessage={setErrorMessage}
setIsActing={setIsActing}
setDidFail={setDidFail}
isAllowed={isAllowed}
setIsAllowed={setIsAllowed}
/>
<PerformButton
isDisabled={isActing || isInvalid}
isActing={isActing}
buttonText={"Reject Bid"}
performAction={rejectBid}
isAllowed={isAllowed}
/>
</Form>

Expand Down
2 changes: 1 addition & 1 deletion components/wrap/WrapModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ function WrapModal({
style={{ width: "128px" }}
disabled={isWrapping}
>
{isWrapping ? "Wrapping..." : `Wrap to ${PAYMENT_TOKEN}`}
{isWrapping ? "Wrapping..." : `Wrap ETH to ${PAYMENT_TOKEN}`}
</Button>
</form>
</Modal.Footer>
Expand Down
Empty file removed lib/wallets/connectors.js
Empty file.
1 change: 1 addition & 0 deletions public/task-done.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion tsconfig.tsbuildinfo

This file was deleted.