Skip to content

Commit

Permalink
Merge pull request #149 from unicrowio/ext-payment
Browse files Browse the repository at this point in the history
Ext payment
  • Loading branch information
ps1dr3x committed Nov 21, 2023
2 parents a788676 + 6db69d5 commit 2f9dedc
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 21 deletions.
1 change: 1 addition & 0 deletions src/config/marker.ts
Expand Up @@ -14,4 +14,5 @@ export const MARKER = {
challengePeriod: "How long will it be possible to challenge the payment",
challengePeriodExtension:
"How long will a new challenge period last after a challenge",
reference: "A reference for the payment",
};
2 changes: 2 additions & 0 deletions src/indexer/internal/payload.ts
Expand Up @@ -42,4 +42,6 @@ export const returningValues = [
"amount_protocol",
"amount_arbitrator",
"amount_marketplace",
"reference",
"status",
];
4 changes: 4 additions & 0 deletions src/typing/index.ts
Expand Up @@ -39,6 +39,10 @@ export interface IPaymentProps {
arbitratorFee?: number;
/** By how much will the challenge period get extended after a challenge (in seconds) */
challengePeriodExtension?: number;
/** (UI only) A reference for the payment to display */
reference?: string;
/** (UI only) A url to redirect to, when the payment is done or canceled */
callbackUrl?: string;
}

export interface IValidateProps extends IPaymentProps {
Expand Down
11 changes: 8 additions & 3 deletions src/ui/internal/components/ScopedModal.tsx
Expand Up @@ -19,6 +19,7 @@ interface ScopedModalProps {
footer: ReactNode;
isLoading: boolean;
loadingMessage: string;
closeable?: boolean;
onClose?: () => any;
modalAction?: any;
}
Expand Down Expand Up @@ -78,9 +79,13 @@ export const ScopedModal: React.FunctionComponent<ScopedModalProps> = (
<Modal isLoading={props.isLoading} loadingMessage={props.loadingMessage}>
<ModalHeader>
<ModalHeaderTitle>{props.title}</ModalHeaderTitle>
<ModalHeaderClose onClick={props.onClose}>
<CloseIcon />
</ModalHeaderClose>
{props.closeable ? (
<ModalHeaderClose onClick={props.onClose}>
<CloseIcon />
</ModalHeaderClose>
) : (
<></>
)}
</ModalHeader>
<BodyWithFooter />
</Modal>
Expand Down
86 changes: 68 additions & 18 deletions src/ui/internal/modals/Pay.tsx
Expand Up @@ -52,15 +52,39 @@ export function PayModal(props: IPaymentModalProps) {
error: errorToken,
} = useTokenInfo(props.paymentProps.tokenAddress);

const closeHandlerRef = useModalCloseHandler(onModalClose);
const closeHandlerRef = useModalCloseHandler(
props.paymentProps?.callbackUrl ? () => {} : onModalClose,
);
const [modalTitle, setModalTitle] = React.useState("Payment");
const [paymentStatus, setPaymentStatus] = React.useState<EscrowStatus>(
EscrowStatus.UNPAID,
);
const [buyer, setBuyer] = React.useState<string | null>();
const [callbackCountdown, setCallbackCountdown] = React.useState<number>(10);
const [startCountdown, setStartCountdown] = React.useState<boolean>(false);
const isLoadingAnything = isLoadingToken || isLoadingWallet || isLoading;
const error = errorWallet || errorToken;

React.useEffect(() => {
let interval;

if (startCountdown) {
if (callbackCountdown > 0) {
interval = setInterval(() => {
setCallbackCountdown((currentCount) => Math.max(currentCount - 1, 0));
}, 1000);
} else {
window.location.href = props.paymentProps.callbackUrl;
}
}

return () => {
if (interval) {
clearInterval(interval);
}
};
}, [startCountdown, callbackCountdown]);

const payCallbacks: IPayTransactionCallbacks = {
connectingWallet: () => {
setIsLoading(true);
Expand Down Expand Up @@ -180,19 +204,16 @@ export function PayModal(props: IPaymentModalProps) {
/>
</>
)}
{props.paymentProps.marketplace &&
props.paymentProps.marketplace?.toLowerCase() !==
ADDRESS_ZERO.toLowerCase() && (
<DataDisplayer
label="Marketplace Address"
value={reduceAddress(
props.paymentProps.marketplace,
props.paymentProps.ensAddresses?.marketplace,
)}
copy={props.paymentProps.marketplace}
marker={MARKER.marketplace}
/>
)}
{props.paymentProps.reference ? (
<DataDisplayer
label="Reference"
value={props.paymentProps.reference}
copy={props.paymentProps.reference}
marker={MARKER.reference}
/>
) : (
<></>
)}
</ContainerDataDisplayer>
</>
);
Expand All @@ -201,6 +222,23 @@ export function PayModal(props: IPaymentModalProps) {
const ModalFooter = () => {
let buttonChildren;
let buttonOnClick;
let buttonCallback = <></>;

if (props.paymentProps?.callbackUrl) {
buttonCallback = (
<Button
fullWidth
variant="tertiary"
style={{ marginTop: 15 }}
disabled={isLoadingAnything}
onClick={() =>
(window.location.href = props.paymentProps.callbackUrl)
}
>
Cancel
</Button>
);
}

if (!(error || success)) {
buttonChildren = `Pay ${props.paymentProps.amount} ${
Expand All @@ -209,16 +247,27 @@ export function PayModal(props: IPaymentModalProps) {
buttonOnClick = onPayClick;
} else if (success) {
buttonChildren = "Close";
buttonOnClick = onModalClose;
if (props.paymentProps?.callbackUrl) {
setStartCountdown(true);
buttonChildren = `Back to merchant in ... ${callbackCountdown}s`;
buttonCallback = <></>;
buttonOnClick = () =>
(window.location.href = props.paymentProps.callbackUrl);
} else {
buttonOnClick = onModalClose;
}
} else {
buttonChildren = "Retry";
buttonOnClick = onPayClick;
}

return (
<Button fullWidth disabled={isLoadingAnything} onClick={buttonOnClick}>
{buttonChildren}
</Button>
<>
<Button fullWidth disabled={isLoadingAnything} onClick={buttonOnClick}>
{buttonChildren}
</Button>
{buttonCallback}
</>
);
};

Expand All @@ -228,6 +277,7 @@ export function PayModal(props: IPaymentModalProps) {
title={modalTitle}
body={<ModalBody />}
footer={<ModalFooter />}
closeable={props.paymentProps?.callbackUrl ? false : true}
onClose={onModalClose}
isLoading={isLoadingAnything}
loadingMessage={loadingMessage}
Expand Down

0 comments on commit 2f9dedc

Please sign in to comment.