Skip to content

Commit

Permalink
feat: commit widget
Browse files Browse the repository at this point in the history
  • Loading branch information
albertfolch-redeemeum committed Nov 27, 2023
1 parent f2ab29e commit 7a08f36
Show file tree
Hide file tree
Showing 33 changed files with 1,383 additions and 348 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
import React, { useCallback, useEffect, useState } from "react";
import { theme } from "../../../../theme";
import { useAccount } from "../../../../hooks/connection/connection";
import { useDisconnect } from "../../../../hooks/connection/useDisconnect";
import { OfferFullDescriptionView } from "./OfferFullDescriptionView/OfferFullDescriptionView";
import { ReturnUseProductByUuid } from "../../../../hooks/products/useProductByUuid";
import { Offer } from "../../../../types/offer";
import { VariantV1 } from "../../../../types/variants";
import { OfferVariantView, OfferVariantViewProps } from "./OfferVariantView";
import NonModal, { NonModalProps } from "../../nonModal/NonModal";
import Typography from "../../../ui/Typography";
import { BosonFooter } from "../common/BosonFooter";
import { useConfigContext } from "../../../config/ConfigContext";
import { Loading } from "../../../Loading";
import { PurchaseOverviewView } from "../common/StepsOverview/PurchaseOverviewView";
import { CommitOfferPolicyView } from "./OfferPolicyView/CommitOfferPolicyView";
import useCheckExchangePolicy from "../../../../hooks/useCheckExchangePolicy";
import { useConvertionRate } from "../../../widgets/finance/convertion-rate/useConvertionRate";
import { ContractualAgreementView } from "./ContractualAgreementView/ContractualAgreementView";
import { LicenseAgreementView } from "./LicenseAgreementView/LicenseAgreementView";
import { CommitSuccess } from "./CommitSuccess";
import { Exchange } from "../../../../types/exchange";

const colors = theme.colors.light;
enum ActiveStep {
OFFER_VIEW,
PURCHASE_OVERVIEW,
COMMIT_SUCESS,
EXCHANGE_POLICY,
CONTRACTUAL_AGREEMENT,
LICENSE_AGREEMENT,
OFFER_FULL_DESCRIPTION
}

export type CommitNonModalProps = {
product?: ReturnUseProductByUuid;
singleOffer?: Offer;
isLoading: boolean;
fairExchangePolicyRules: string;
hideModal?: NonModalProps["hideModal"];
offerViewOnExchangePolicyClick?: OfferVariantViewProps["onExchangePolicyClick"];
offerViewOnPurchaseOverview?: OfferVariantViewProps["onPurchaseOverview"];
offerViewOnViewFullDescription?: OfferVariantViewProps["onViewFullDescription"];
forcedAccount?: string;
};

export default function CommitWrapper({
hideModal,
...props
}: CommitNonModalProps) {
return (
<NonModal
props={{
hideModal,
headerComponent: (
<Typography tag="h3" $width="100%">
Commit
</Typography>
),
footerComponent: <BosonFooter />,
contentStyle: {
background: colors.white
}
}}
>
<CommitNonModal hideModal={hideModal} {...props} />
</NonModal>
);
}

function CommitNonModal({
singleOffer,
product: productResult,
isLoading,
fairExchangePolicyRules,
offerViewOnExchangePolicyClick,
offerViewOnPurchaseOverview,
offerViewOnViewFullDescription,
forcedAccount,
hideModal
}: CommitNonModalProps) {
const variants = productResult?.variants;
const variantsWithV1 = variants?.filter(
({ offer: { metadata } }) => metadata?.type === "PRODUCT_V1"
) as VariantV1[] | undefined;
const singleOfferVariant = singleOffer
? { offer: singleOffer, variations: [] }
: undefined;
const defaultVariant =
variantsWithV1?.find((variant) => !variant.offer.voided) ??
variantsWithV1?.[0] ??
singleOfferVariant;

const [exchange, setExchange] = useState<Exchange | null>(null);
const [selectedVariant, setSelectedVariant] = useState<VariantV1 | undefined>(
defaultVariant
);
useEffect(() => {
if (defaultVariant) {
setSelectedVariant(defaultVariant);
}
}, [defaultVariant]);
const {
store: { tokens: defaultTokens }
} = useConvertionRate();
const { config: coreConfig } = useConfigContext();
const defaultDisputeResolverId = coreConfig?.defaultDisputeResolverId;

const [{ currentStep }, setStep] = useState<{
previousStep: ActiveStep[];
currentStep: ActiveStep;
}>({
previousStep: [],
currentStep: ActiveStep.OFFER_VIEW
});

const setActiveStep = (newCurrentStep: ActiveStep) => {
setStep((prev) => ({
previousStep: [...prev.previousStep, prev.currentStep],
currentStep: newCurrentStep
}));
};
const goToPreviousStep = useCallback(() => {
setStep((prev) => {
const { previousStep } = prev;
const currentStep = previousStep.length
? (previousStep.pop() as ActiveStep)
: prev.currentStep;
const previousWithoutLast = previousStep;
return {
previousStep: previousWithoutLast,
currentStep: currentStep
};
});
}, []);
const { address } = useAccount();
const disconnect = useDisconnect();
const exchangePolicyCheckResult = useCheckExchangePolicy({
offerId: selectedVariant?.offer?.id,
fairExchangePolicyRules,
defaultDisputeResolverId: defaultDisputeResolverId || "unknown",
defaultTokens: defaultTokens || []
});
if (
forcedAccount &&
address &&
forcedAccount.toLowerCase() !== address.toLowerCase()
) {
// force disconnection as the current connected wallet is not the forced one
disconnect();
}

if (!address) {
return (
<>
<p>Please connect your wallet</p>
{forcedAccount && <p>(expected account: {forcedAccount})</p>}
</>
);
}
if (isLoading) {
return <Loading />;
}

if (!selectedVariant) {
return <p>No variant has been selected</p>;
}

return (
<>
{currentStep === ActiveStep.OFFER_VIEW ? (
<OfferVariantView
variant={selectedVariant}
onExchangePolicyClick={() => {
setActiveStep(ActiveStep.EXCHANGE_POLICY);
offerViewOnExchangePolicyClick?.();
}}
onPurchaseOverview={() => {
setActiveStep(ActiveStep.PURCHASE_OVERVIEW);
offerViewOnPurchaseOverview?.();
}}
onViewFullDescription={() => {
setActiveStep(ActiveStep.OFFER_FULL_DESCRIPTION);
offerViewOnViewFullDescription?.();
}}
onNextClick={() => {
setActiveStep(ActiveStep.COMMIT_SUCESS);
// TODO: call to setExchange(exchange)
}}
fairExchangePolicyRules={fairExchangePolicyRules}
defaultDisputeResolverId={defaultDisputeResolverId}
/>
) : currentStep === ActiveStep.OFFER_FULL_DESCRIPTION ? (
<OfferFullDescriptionView
onBackClick={goToPreviousStep}
offer={selectedVariant.offer}
/>
) : currentStep === ActiveStep.PURCHASE_OVERVIEW ? (
<PurchaseOverviewView onBackClick={goToPreviousStep} />
) : currentStep === ActiveStep.EXCHANGE_POLICY ? (
<CommitOfferPolicyView
offer={selectedVariant.offer}
onBackClick={goToPreviousStep}
onContractualAgreementClick={() =>
setActiveStep(ActiveStep.CONTRACTUAL_AGREEMENT)
}
onLicenseAgreementClick={() =>
setActiveStep(ActiveStep.LICENSE_AGREEMENT)
}
exchangePolicyCheckResult={exchangePolicyCheckResult}
/>
) : currentStep === ActiveStep.CONTRACTUAL_AGREEMENT ? (
<ContractualAgreementView
offer={selectedVariant.offer}
onBackClick={goToPreviousStep}
/>
) : currentStep === ActiveStep.LICENSE_AGREEMENT ? (
<LicenseAgreementView
offer={selectedVariant.offer}
onBackClick={goToPreviousStep}
/>
) : currentStep === ActiveStep.COMMIT_SUCESS ? (
<CommitSuccess
onHouseClick={() => setActiveStep(ActiveStep.OFFER_VIEW)}
onClickDone={() => hideModal?.()}
onExchangePolicyClick={() =>
setActiveStep(ActiveStep.EXCHANGE_POLICY)
}
exchangeId={exchange?.id || ""}
/>
) : (
<p>Wrong step...something went wrong</p>
)}
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { CheckCircle, Fire, House } from "phosphor-react";
import React, { useEffect } from "react";
import styled from "styled-components";
import { getOfferDetails } from "../../../../lib/offer/getOfferDetails";
import Grid from "../../../ui/Grid";
import IpfsImage from "../../../ui/IpfsImage";
import Loading from "../../../ui/loading/Loading";
import Typography from "../../../ui/Typography";
import { theme } from "../../../../theme";
import Video from "../../../ui/Video";
import { Button } from "../../../buttons/Button";
import GridContainer from "../../../ui/GridContainer";
import { useNonModalContext } from "../../nonModal/NonModal";
import { useExchanges } from "../../../../hooks/useExchanges";
import DetailOpenSea from "../common/DetailOpenSea";

const colors = theme.colors.light;

const ImageWrapper = styled.div`
position: relative;
max-width: 35rem !important;
min-width: 50%;
width: -webkit-fill-available;
`;

type Props = {
onClickDone: () => void;
onHouseClick: () => void;
onExchangePolicyClick: () => void;
exchangeId: string;
};

export function CommitSuccess({
onClickDone,
onHouseClick,
exchangeId
}: Props) {
const {
data: exchanges,
isError,
isFetching
} = useExchanges(
{
id: exchangeId
},
{
enabled: !!exchangeId
}
);
const exchange = exchanges?.[0];
const offer = exchange?.offer;

const offerDetails = offer ? getOfferDetails(offer) : undefined;
const dispatch = useNonModalContext();
useEffect(() => {
dispatch({
payload: {
headerComponent: (
<Grid>
<House
onClick={onHouseClick}
size={32}
style={{ cursor: "pointer", flexShrink: 0 }}
/>
<Typography tag="h3" $width="100%">
Sucess!
</Typography>
</Grid>
),
contentStyle: {
background: colors.lightGrey
}
}
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dispatch]);
return (
<>
{isFetching ? (
<Loading />
) : !offer ? (
<div data-testid="notFound">This exchange does not exist</div>
) : isError || !exchangeId || !offerDetails ? (
<div data-testid="errorExchange">
There has been an error, please try again later...
</div>
) : (
<GridContainer
itemsPerRow={{
xs: 2,
s: 2,
m: 2,
l: 2,
xl: 2
}}
>
<ImageWrapper>
{offerDetails.animationUrl ? (
<Video
src={offerDetails.animationUrl}
dataTestId="offerAnimationUrl"
videoProps={{ muted: true, loop: true, autoPlay: true }}
componentWhileLoading={() => (
<IpfsImage
src={offerDetails.offerImg}
dataTestId="offerImage"
/>
)}
/>
) : (
<IpfsImage src={offerDetails.offerImg} dataTestId="offerImage" />
)}
<DetailOpenSea exchange={exchange} />
</ImageWrapper>
<Grid flexDirection="column" gap="1rem">
<Grid
as="section"
style={{ background: colors.white, padding: "2rem" }}
gap="1rem"
>
<CheckCircle size="60" color={colors.green} />
<Grid flexDirection="column" alignItems="flex-start">
<Typography fontWeight="600" $fontSize="1.25rem">
Congratulations!
</Typography>
</Grid>
</Grid>
<Grid
as="section"
gap="1.5rem"
style={{ background: colors.white, padding: "2rem" }}
flexDirection="column"
>
<Grid flex="1 1" alignItems="flex-start" gap="1rem">
<div>
<Typography fontWeight="600">What's next?</Typography>
<Typography tag="p">Redeem it!</Typography>
</div>
</Grid>
<Grid
style={{ background: colors.lightGrey, padding: "1.5rem" }}
justifyContent="flex-start"
gap="1rem"
>
<Fire size={25} color={colors.orange} />
<Typography>You got an rNFT</Typography>
</Grid>
</Grid>

<Grid
as="section"
justifyContent="flex-end"
style={{ background: colors.white, padding: "2rem" }}
>
<Button onClick={onClickDone}>Done</Button>
</Grid>
</Grid>
</GridContainer>
)}
</>
);
}
Loading

0 comments on commit 7a08f36

Please sign in to comment.