diff --git a/src/components/product/CoreTermsOfSale.tsx b/src/components/product/coreTermsOfSale/CoreTermsOfSale.tsx
similarity index 85%
rename from src/components/product/CoreTermsOfSale.tsx
rename to src/components/product/coreTermsOfSale/CoreTermsOfSale.tsx
index d15d91ecb..1cb684b0c 100644
--- a/src/components/product/CoreTermsOfSale.tsx
+++ b/src/components/product/coreTermsOfSale/CoreTermsOfSale.tsx
@@ -1,21 +1,22 @@
import { useState } from "react";
import styled from "styled-components";
-import { useCoreSDK } from "../../lib/utils/useCoreSdk";
-import { Datepicker, FormField, Input, Select, Textarea } from "../form";
-import BosonButton from "../ui/BosonButton";
+import { useCoreSDK } from "../../../lib/utils/useCoreSdk";
+import { FormField, Input, Select, Textarea } from "../../form";
+import BosonButton from "../../ui/BosonButton";
import {
ContainerProductPage,
ProductButtonGroup,
SectionTitle
-} from "./Product.styles";
+} from "../Product.styles";
import {
OPTIONS_CURRENCIES,
OPTIONS_TOKEN_GATED,
TOKEN_CRITERIA,
TOKEN_TYPES
-} from "./utils";
-import { useCreateForm } from "./utils/useCreateForm";
+} from "../utils";
+import { useCreateForm } from "../utils/useCreateForm";
+import { CoreTermsOfSaleDates } from "./CoreTermsOfSaleDates";
const PriceContainer = styled.div`
display: grid;
@@ -97,16 +98,6 @@ export default function CoreTermsOfSale({ isMultiVariant }: Props) {
{values[prefix].tokenGatedOffer.value === "true" && (
<>
- {/* TODO: enable once we have more than one variant */}
- {/*
-
-
-
- */}
-
)}
-
-
-
-
-
-
+
= ({
+ prefix
+}) => {
+ const fixedPrefix = prefix ? `${prefix}.` : "";
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/src/components/product/utils/const.ts b/src/components/product/utils/const.ts
index fecd7e2d2..ed435e99a 100644
--- a/src/components/product/utils/const.ts
+++ b/src/components/product/utils/const.ts
@@ -79,14 +79,7 @@ export const OPTIONS_TOKEN_GATED = [
value: "true",
label: "Yes"
}
-];
-
-export const TOKEN_GATED_VARIANTS = [
- {
- value: "all",
- label: "All"
- }
-];
+] as const;
export const TOKEN_TYPES = [
{
@@ -101,7 +94,7 @@ export const TOKEN_TYPES = [
value: "erc1155",
label: "ERC1155"
}
-];
+] as const;
export const TOKEN_CRITERIA = [
{
@@ -112,7 +105,7 @@ export const TOKEN_CRITERIA = [
value: "tokenid",
label: "tokenId"
}
-];
+] as const;
export const OPTIONS_EXCHANGE_POLICY = [
{
diff --git a/src/components/product/utils/initialValues.ts b/src/components/product/utils/initialValues.ts
index 7322b0c97..0656f1f07 100644
--- a/src/components/product/utils/initialValues.ts
+++ b/src/components/product/utils/initialValues.ts
@@ -11,7 +11,6 @@ import {
OPTIONS_UNIT,
OPTIONS_WEIGHT,
TOKEN_CRITERIA,
- TOKEN_GATED_VARIANTS,
TOKEN_TYPES
} from "./const";
import { CreateProductForm } from "./types";
@@ -89,7 +88,6 @@ export const coreTermsOfSaleInitialValues = {
currency: OPTIONS_CURRENCIES[0],
quantity: 1,
tokenGatedOffer: OPTIONS_TOKEN_GATED[0],
- tokenGatedVariants: TOKEN_GATED_VARIANTS[0],
tokenContract: "",
tokenType: TOKEN_TYPES[0],
minBalance: undefined,
@@ -105,7 +103,6 @@ export const coreTermsOfSaleInitialValues = {
export const variantsCoreTermsOfSaleInitialValues = {
variantsCoreTermsOfSale: {
tokenGatedOffer: OPTIONS_TOKEN_GATED[0],
- tokenGatedVariants: TOKEN_GATED_VARIANTS[0],
tokenContract: "",
tokenType: TOKEN_TYPES[0],
minBalance: undefined,
diff --git a/src/components/product/utils/validationSchema.ts b/src/components/product/utils/validationSchema.ts
index a75ccb2cb..76e22db7a 100644
--- a/src/components/product/utils/validationSchema.ts
+++ b/src/components/product/utils/validationSchema.ts
@@ -175,30 +175,23 @@ export const productInformationValidationSchema = Yup.object({
})
});
-const commonCoreTermsOfSaleValidationSchema = {
+export const commonCoreTermsOfSaleValidationSchema = {
tokenGatedOffer: Yup.object()
.shape({
value: Yup.string(),
label: Yup.string()
})
.default([{ value: "", label: "" }]),
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- offerValidityPeriod: Yup.mixed().isItBeforeNow().isOfferValidityDatesValid(), // prettier-ignore
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- redemptionPeriod: Yup.mixed().isItBeforeNow().isRedemptionDatesValid(), // prettier-ignore
- tokenGatedVariants: Yup.object()
- .when(["tokenGatedOffer"], {
- is: (tokenGated: SelectDataProps) =>
- tokenGated?.value === OPTIONS_TOKEN_GATED[1].value,
- then: (schema) => schema.required(validationMessage.required)
- })
- .shape({
- value: Yup.string(),
- label: Yup.string()
- })
- .default([{ value: "", label: "" }]),
+ offerValidityPeriod: Yup.array()
+ .required(validationMessage.required)
+ .min(2, validationMessage.required)
+ .isItBeforeNow()
+ .isOfferValidityDatesValid(),
+ redemptionPeriod: Yup.array()
+ .required(validationMessage.required)
+ .min(2, validationMessage.required)
+ .isItBeforeNow()
+ .isRedemptionDatesValid(),
tokenContract: Yup.string()
.when(["tokenGatedOffer"], {
is: (tokenGated: SelectDataProps) =>
@@ -226,17 +219,14 @@ const commonCoreTermsOfSaleValidationSchema = {
label: Yup.string()
})
.default([{ value: "", label: "" }]),
- tokenCriteria: Yup.object()
- .when(["tokenGatedOffer"], {
- is: (tokenGated: SelectDataProps) =>
- tokenGated?.value === OPTIONS_TOKEN_GATED[1].value,
- then: (schema) => schema.required(validationMessage.required)
- })
- .shape({
- value: Yup.string(),
- label: Yup.string()
- })
- .default([{ value: "", label: "" }]),
+ tokenCriteria: Yup.object({
+ value: Yup.string(),
+ label: Yup.string()
+ }).when(["tokenGatedOffer"], {
+ is: (tokenGated: SelectDataProps) =>
+ tokenGated?.value === OPTIONS_TOKEN_GATED[1].value,
+ then: (schema) => schema.required(validationMessage.required)
+ }),
minBalance: Yup.string().when(
["tokenGatedOffer", "tokenType", "tokenCriteria"],
{
diff --git a/src/components/seller/SellerWrapper.tsx b/src/components/seller/SellerWrapper.tsx
index f9aa6c00c..d353048b6 100644
--- a/src/components/seller/SellerWrapper.tsx
+++ b/src/components/seller/SellerWrapper.tsx
@@ -7,6 +7,7 @@ const SellerMain = styled.main`
padding: 1.375rem 2.5rem 2.75rem 2.5rem;
background: ${colors.lightGrey};
min-height: calc(100vh - 5.5rem);
+ overflow: hidden;
`;
const SellerTitle = styled(Typography)`
margin: 0 0 1.25rem 0;
@@ -16,6 +17,7 @@ const SellerInner = styled.div`
padding: 1rem;
box-shadow: 0px 0px 5px 0px rgb(0 0 0 / 2%), 0px 0px 10px 0px rgb(0 0 0 / 2%),
0px 0px 15px 0px rgb(0 0 0 / 5%);
+ overflow: auto;
`;
export const LoadingWrapper = styled.div`
text-align: center;
diff --git a/src/components/seller/exchanges/SellerExchanges.tsx b/src/components/seller/exchanges/SellerExchanges.tsx
index a8dd0bbda..6d6d67b3b 100644
--- a/src/components/seller/exchanges/SellerExchanges.tsx
+++ b/src/components/seller/exchanges/SellerExchanges.tsx
@@ -180,7 +180,7 @@ export default function SellerExchanges({
const [csvData, setCsvData] = useState([] as CSVData[]);
const [loading, setLoading] = useState(false);
- const { initialize, bosonXmtp, isInitializing } = useChatContext();
+ const { initialize, bosonXmtp, isInitializing, error } = useChatContext();
const worker = useWorker(createWorker);
const location = useLocation();
@@ -568,6 +568,12 @@ export default function SellerExchanges({
}
);
+ useEffect(() => {
+ if ((bosonXmtp && loading) || error) {
+ setLoading(false);
+ }
+ }, [bosonXmtp, loading, error]);
+
useEffect(() => {
if (bosonXmtp && loading && csvData.length === 0) {
showExchangesExportModal();
diff --git a/src/components/seller/products/SellerProductsTable.tsx b/src/components/seller/products/SellerProductsTable.tsx
index 60164d3e0..42505665a 100644
--- a/src/components/seller/products/SellerProductsTable.tsx
+++ b/src/components/seller/products/SellerProductsTable.tsx
@@ -244,6 +244,11 @@ const Span = styled.span`
margin-right: 1rem;
}
`;
+const RelistButton = styled(Button)`
+ * {
+ line-height: 21px;
+ }
+`;
const statusOrder = [
OffersKit.OfferState.NOT_YET_VALID,
@@ -623,7 +628,7 @@ export default function SellerProductsTable({
/>
),
quantity: (
-
+
{offer?.quantityAvailable}/{offer?.quantityInitial}
),
@@ -644,56 +649,89 @@ export default function SellerProductsTable({
),
- action: !(
- status === OffersKit.OfferState.EXPIRED ||
- status === OffersKit.OfferState.VOIDED ||
- offer?.quantityAvailable === "0"
- ) && (
- {
- if (offer) {
- if (showVariant) {
- showModal(
- modalTypes.VOID_PRODUCT,
- {
- title: "Void Confirmation",
- offers: offer.additional?.variants.filter(
- (variant) => {
- variant.validUntilDate;
- return (
- !variant.voided &&
- !dayjs(
- getDateTimestamp(offer?.validUntilDate)
- ).isBefore(dayjs())
- );
- }
- ) as Offer[],
- refetch
- },
- "s"
- );
- } else {
- showModal(
- modalTypes.VOID_PRODUCT,
- {
- title: "Void Confirmation",
- offerId: offer.id,
- offer,
- refetch
- },
- "xs"
- );
- }
- }
- }}
- >
- Void
-
- )
+ action: (() => {
+ const withVoidButton = !(
+ status === OffersKit.OfferState.EXPIRED ||
+ status === OffersKit.OfferState.VOIDED ||
+ offer?.quantityAvailable === "0"
+ );
+ return (
+
+ {withVoidButton && (
+ {
+ if (offer) {
+ if (showVariant) {
+ showModal(
+ modalTypes.VOID_PRODUCT,
+ {
+ title: "Void Confirmation",
+ offers: offer.additional?.variants.filter(
+ (variant) => {
+ variant.validUntilDate;
+ return (
+ !variant.voided &&
+ !dayjs(
+ getDateTimestamp(offer?.validUntilDate)
+ ).isBefore(dayjs())
+ );
+ }
+ ) as Offer[],
+ refetch
+ },
+ "s"
+ );
+ } else {
+ showModal(
+ modalTypes.VOID_PRODUCT,
+ {
+ title: "Void Confirmation",
+ offerId: offer.id,
+ offer,
+ refetch
+ },
+ "xs"
+ );
+ }
+ }
+ }}
+ >
+ Void
+
+ )}
+ [0]["onClick"]>
+ >[0]
+ ) => {
+ event.stopPropagation();
+ if (!offer) {
+ return;
+ }
+ showModal(modalTypes.RELIST_OFFER, {
+ title: `Relist Offer "${offer.metadata.name}"`,
+ offer,
+ onRelistedSuccessfully: refetch
+ });
+ }}
+ >
+ Relist
+
+
+ );
+ })()
};
})
.sort(compareOffersSortByStatus),
diff --git a/src/components/toasts/SuccessTransactionToast.tsx b/src/components/toasts/SuccessTransactionToast.tsx
index dd202f73a..981b372bb 100644
--- a/src/components/toasts/SuccessTransactionToast.tsx
+++ b/src/components/toasts/SuccessTransactionToast.tsx
@@ -1,6 +1,7 @@
import { Toast } from "react-hot-toast";
import { colors } from "../../lib/styles/colors";
+import { sanitizeUrl } from "../../lib/utils/url";
import Grid from "../ui/Grid";
import Typography from "../ui/Typography";
import SuccessToast from "./common/SuccessToast";
@@ -33,7 +34,7 @@ export default function SuccessTransactionToast({
View details
) : url ? (
-
+
View details
) : null}
diff --git a/src/lib/styles/GlobalStyle.tsx b/src/lib/styles/GlobalStyle.tsx
index 36752c3fc..b009e74ea 100644
--- a/src/lib/styles/GlobalStyle.tsx
+++ b/src/lib/styles/GlobalStyle.tsx
@@ -1,5 +1,7 @@
import { createGlobalStyle } from "styled-components";
+import barlowRegular from "../../assets/fonts/Barlow-Regular.ttf";
+import neuropolitical_rg from "../../assets/fonts/neuropolitical_rg.ttf";
import { breakpoint } from "../../lib/styles/breakpoint";
import { colors } from "../../lib/styles/colors";
@@ -19,7 +21,12 @@ const GlobalStyle = createGlobalStyle<{
}>`
@font-face {
font-family: barlow;
- src: url(src/assets/fonts/Barlow-Regular.ttf);
+ src: url(${barlowRegular});
+ font-weight: normal;
+ }
+ @font-face {
+ font-family: neuropolitical_rg;
+ src: url(${neuropolitical_rg});
font-weight: normal;
}
* {
diff --git a/src/lib/types/externals.d.ts b/src/lib/types/externals.d.ts
index 7c5b8894e..ec5f4ff93 100644
--- a/src/lib/types/externals.d.ts
+++ b/src/lib/types/externals.d.ts
@@ -1,3 +1,5 @@
declare module "@metamask/jazzicon";
declare module "pretty";
+
+declare module "*.ttf";
diff --git a/src/lib/types/yup.d.ts b/src/lib/types/yup.d.ts
new file mode 100644
index 000000000..eab5992ff
--- /dev/null
+++ b/src/lib/types/yup.d.ts
@@ -0,0 +1,24 @@
+import type { Dayjs } from "dayjs";
+import * as yup from "yup";
+declare module "yup" {
+ interface StringSchema<
+ TType extends Maybe = string | undefined,
+ TContext extends AnyObject = AnyObject,
+ TOut extends TType = TType
+ > extends yup.BaseSchema {
+ emptyAsUndefined(): StringSchema;
+ }
+ interface ArraySchema<
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ T extends AnySchema | Lazy,
+ C extends AnyObject = AnyObject,
+ TIn extends Maybe[]> = TypeOf[] | undefined,
+ TOut extends Maybe[]> = Asserts[] | Optionals
+ > extends BaseSchema {
+ isItBeforeNow(): ArraySchema;
+ isOfferValidityDatesValid(): ArraySchema;
+ isRedemptionDatesValid(): ArraySchema;
+ }
+}
+
+export default yup;
diff --git a/src/lib/utils/hooks/offer/useCreateOffers.tsx b/src/lib/utils/hooks/offer/useCreateOffers.tsx
new file mode 100644
index 000000000..5adc2c611
--- /dev/null
+++ b/src/lib/utils/hooks/offer/useCreateOffers.tsx
@@ -0,0 +1,332 @@
+import { offers, subgraph } from "@bosonprotocol/react-kit";
+import { useMutation } from "react-query";
+import { useAccount } from "wagmi";
+
+import { authTokenTypes } from "../../../../components/modal/components/CreateProfile/Lens/const";
+import { useModal } from "../../../../components/modal/useModal";
+import { TOKEN_TYPES } from "../../../../components/product/utils";
+import { poll } from "../../../../pages/create-product/utils";
+import {
+ buildCondition,
+ CommonTermsOfSale
+} from "../../../../pages/create-product/utils/buildCondition";
+import { useCoreSDK } from "../../useCoreSdk";
+import { useAddPendingTransaction } from "../transactions/usePendingTransactions";
+import { useCurrentSellers } from "../useCurrentSellers";
+
+type OfferFieldsFragment = subgraph.OfferFieldsFragment;
+
+type UseCreateOffersProps = {
+ offersToCreate: offers.CreateOfferArgs[];
+ isMultiVariant: boolean;
+ tokenGatedInfo?: CommonTermsOfSale | null;
+ conditionDecimals?: number;
+ onGetExchangeTokenDecimals?: (decimals: number | undefined) => unknown;
+ onCreatedOffersWithVariants?: (arg0: {
+ firstOffer: OfferFieldsFragment;
+ }) => void;
+ onCreatedSingleOffers?: (arg0: { offer: OfferFieldsFragment }) => void;
+};
+
+export function useCreateOffers() {
+ const coreSDK = useCoreSDK();
+ const { sellers } = useCurrentSellers();
+ const { address } = useAccount();
+ const { showModal, hideModal } = useModal();
+ const addPendingTransaction = useAddPendingTransaction();
+ const isMetaTx = Boolean(coreSDK.isMetaTxConfigSet && address);
+ return useMutation(
+ async ({
+ offersToCreate,
+ isMultiVariant,
+ tokenGatedInfo,
+ conditionDecimals,
+ onGetExchangeTokenDecimals,
+ onCreatedOffersWithVariants,
+ onCreatedSingleOffers
+ }: UseCreateOffersProps) => {
+ const isTokenGated = !!tokenGatedInfo;
+ const onBeforeBuildCondition = async () => {
+ let decimalsLocal: number | undefined = conditionDecimals;
+ if (
+ tokenGatedInfo?.tokenContract &&
+ tokenGatedInfo.tokenType?.value === TOKEN_TYPES[0].value
+ ) {
+ try {
+ const { decimals: tokenDecimals } =
+ await coreSDK.getExchangeTokenInfo(tokenGatedInfo.tokenContract);
+ decimalsLocal = tokenDecimals;
+ onGetExchangeTokenDecimals?.(decimalsLocal);
+ } catch (error) {
+ decimalsLocal = undefined;
+ onGetExchangeTokenDecimals?.(decimalsLocal);
+ }
+ }
+ return decimalsLocal;
+ };
+ showModal("WAITING_FOR_CONFIRMATION");
+ const hasSellerAccount = !!sellers?.length;
+ const seller = address
+ ? {
+ operator: address,
+ admin: address,
+ treasury: address,
+ clerk: address,
+ contractUri: "ipfs://sample",
+ royaltyPercentage: "0",
+ authTokenId: "0",
+ authTokenType: authTokenTypes.NONE
+ }
+ : null;
+ let txResponse;
+ if (isMultiVariant) {
+ if (!hasSellerAccount && seller) {
+ if (isMetaTx) {
+ // createSeller with meta-transaction
+ const nonce = Date.now();
+ const { r, s, v, functionName, functionSignature } =
+ await coreSDK.signMetaTxCreateSeller({
+ createSellerArgs: seller,
+ nonce
+ });
+ txResponse = await coreSDK.relayMetaTransaction({
+ functionName,
+ functionSignature,
+ sigR: r,
+ sigS: s,
+ sigV: v,
+ nonce
+ });
+ } else {
+ txResponse = await coreSDK.createSeller(seller);
+ }
+ showModal("TRANSACTION_SUBMITTED", {
+ action: "Create seller",
+ txHash: txResponse.hash
+ });
+ addPendingTransaction({
+ type: subgraph.EventType.SellerCreated,
+ hash: txResponse.hash,
+ isMetaTx,
+ accountType: "Seller"
+ });
+ await txResponse.wait();
+ showModal("WAITING_FOR_CONFIRMATION");
+ }
+ if (isMetaTx) {
+ // createOfferBatch with meta-transaction
+ const nonce = Date.now();
+ const { r, s, v, functionName, functionSignature } =
+ await coreSDK.signMetaTxCreateOfferBatch({
+ createOffersArgs: offersToCreate,
+ nonce
+ });
+ txResponse = await coreSDK.relayMetaTransaction({
+ functionName,
+ functionSignature,
+ sigR: r,
+ sigS: s,
+ sigV: v,
+ nonce
+ });
+ } else {
+ txResponse = await coreSDK.createOfferBatch(offersToCreate);
+ }
+ showModal("TRANSACTION_SUBMITTED", {
+ action: "Create offer with variants",
+ txHash: txResponse.hash
+ });
+ addPendingTransaction({
+ type: subgraph.EventType.OfferCreated,
+ hash: txResponse.hash,
+ isMetaTx,
+ accountType: "Seller"
+ });
+ const txReceipt = await txResponse.wait();
+ const offerIds = coreSDK.getCreatedOfferIdsFromLogs(txReceipt.logs);
+
+ if (isTokenGated) {
+ showModal("WAITING_FOR_CONFIRMATION");
+ const decimals = await onBeforeBuildCondition();
+ const condition = buildCondition(tokenGatedInfo, decimals);
+
+ if (isMetaTx) {
+ const nonce = Date.now();
+ const { r, s, v, functionName, functionSignature } =
+ await coreSDK.signMetaTxCreateGroup({
+ createGroupArgs: { offerIds, ...condition },
+ nonce
+ });
+ txResponse = await coreSDK.relayMetaTransaction({
+ functionName,
+ functionSignature,
+ sigR: r,
+ sigS: s,
+ sigV: v,
+ nonce
+ });
+ } else {
+ txResponse = await coreSDK.createGroup({ offerIds, ...condition });
+ }
+ showModal("TRANSACTION_SUBMITTED", {
+ action: "Create condition group for offers",
+ txHash: txResponse.hash
+ });
+ await txResponse.wait();
+ }
+ let createdOffers: OfferFieldsFragment[] | null = null;
+ await poll(
+ async () => {
+ createdOffers = (
+ await Promise.all(
+ offerIds.map((offerId) =>
+ coreSDK.getOfferById(offerId as string)
+ )
+ )
+ ).filter((offer) => !!offer);
+ return createdOffers;
+ },
+ (offers) => {
+ return offers.length !== offerIds.length;
+ },
+ 500
+ );
+ const [firstOffer] = createdOffers as unknown as OfferFieldsFragment[];
+ onCreatedOffersWithVariants?.({
+ firstOffer
+ });
+ } else {
+ // no variants
+ const [offerData] = offersToCreate;
+ if (isMetaTx) {
+ // meta-transaction
+ if (!hasSellerAccount && seller) {
+ // createSeller with meta-transaction
+ const nonce = Date.now();
+ const { r, s, v, functionName, functionSignature } =
+ await coreSDK.signMetaTxCreateSeller({
+ createSellerArgs: seller,
+ nonce
+ });
+ const createSellerResponse = await coreSDK.relayMetaTransaction({
+ functionName,
+ functionSignature,
+ sigR: r,
+ sigS: s,
+ sigV: v,
+ nonce
+ });
+ showModal("TRANSACTION_SUBMITTED", {
+ action: "Create seller",
+ txHash: createSellerResponse.hash
+ });
+ addPendingTransaction({
+ type: subgraph.EventType.SellerCreated,
+ hash: createSellerResponse.hash,
+ isMetaTx,
+ accountType: "Seller"
+ });
+ await createSellerResponse.wait();
+ showModal("WAITING_FOR_CONFIRMATION");
+ }
+ // createOffer with meta-transaction
+ const nonce = Date.now();
+ if (isTokenGated) {
+ const decimals = await onBeforeBuildCondition();
+ const condition = buildCondition(tokenGatedInfo, decimals);
+ const { r, s, v, functionName, functionSignature } =
+ await coreSDK.signMetaTxCreateOfferWithCondition({
+ offerToCreate: offerData,
+ condition,
+ nonce
+ });
+ txResponse = await coreSDK.relayMetaTransaction({
+ functionName,
+ functionSignature,
+ sigR: r,
+ sigS: s,
+ sigV: v,
+ nonce
+ });
+ } else {
+ const { r, s, v, functionName, functionSignature } =
+ await coreSDK.signMetaTxCreateOffer({
+ createOfferArgs: offerData,
+ nonce
+ });
+ txResponse = await coreSDK.relayMetaTransaction({
+ functionName,
+ functionSignature,
+ sigR: r,
+ sigS: s,
+ sigV: v,
+ nonce
+ });
+ }
+ } else {
+ // no meta tx
+ if (isTokenGated) {
+ const decimals = await onBeforeBuildCondition();
+ const condition = buildCondition(tokenGatedInfo, decimals);
+ txResponse =
+ !hasSellerAccount && seller
+ ? await coreSDK.createSellerAndOfferWithCondition(
+ seller,
+ offerData,
+ condition
+ )
+ : await coreSDK.createOfferWithCondition(offerData, condition);
+ } else {
+ txResponse =
+ !hasSellerAccount && seller
+ ? await coreSDK.createSellerAndOffer(seller, offerData)
+ : await coreSDK.createOffer(offerData);
+ }
+ }
+ showModal("TRANSACTION_SUBMITTED", {
+ action: "Create offer",
+ txHash: txResponse.hash
+ });
+
+ addPendingTransaction({
+ type: subgraph.EventType.OfferCreated,
+ hash: txResponse.hash,
+ isMetaTx,
+ accountType: "Seller"
+ });
+
+ if (!hasSellerAccount && seller) {
+ addPendingTransaction({
+ type: subgraph.EventType.SellerCreated,
+ hash: txResponse.hash,
+ isMetaTx,
+ accountType: "Seller"
+ });
+ }
+
+ const txReceipt = await txResponse.wait();
+ const offerId = coreSDK.getCreatedOfferIdFromLogs(txReceipt.logs);
+ let createdOffer: OfferFieldsFragment | null = null;
+ await poll(
+ async () => {
+ createdOffer = await coreSDK.getOfferById(offerId as string);
+ return createdOffer;
+ },
+ (offer) => {
+ return !offer;
+ },
+ 500
+ );
+ if (!createdOffer) {
+ return;
+ }
+
+ onCreatedSingleOffers?.({
+ offer: createdOffer
+ });
+ }
+
+ hideModal();
+ }
+ );
+}
diff --git a/src/lib/utils/hooks/useDidMountEffect.ts b/src/lib/utils/hooks/useDidMountEffect.ts
new file mode 100644
index 000000000..b43583c64
--- /dev/null
+++ b/src/lib/utils/hooks/useDidMountEffect.ts
@@ -0,0 +1,14 @@
+import { useEffect, useRef } from "react";
+
+type Params = Parameters;
+
+// to have a 'useEffect' that only changes when dependencies change (instead of that + initial render)
+export const useDidMountEffect = (func: Params[0], deps: Params[1]) => {
+ const didMount = useRef(false);
+
+ useEffect(() => {
+ if (didMount.current) func();
+ else didMount.current = true;
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, deps);
+};
diff --git a/src/lib/validation/index.ts b/src/lib/validation/index.ts
index 5a4f9c452..781c39ca4 100644
--- a/src/lib/validation/index.ts
+++ b/src/lib/validation/index.ts
@@ -1,5 +1,4 @@
-// eslint-disable-next-line
-// @ts-nocheck
+import type { Dayjs } from "dayjs";
import * as Yup from "yup";
import disputePeriodValue from "./disputePeriodValue";
@@ -9,17 +8,21 @@ import isOfferValidityDatesValid from "./isOfferValidityDatesValid";
import isRedemptionDatesValid from "./isRedemptionDatesValid";
import returnPeriodValue from "./returnPeriodValue";
-Yup.addMethod(
- Yup.mixed,
+Yup.addMethod>>(
+ Yup.array,
"isRedemptionDatesValid",
isRedemptionDatesValid
);
-Yup.addMethod(
- Yup.mixed,
+Yup.addMethod>>(
+ Yup.array,
"isOfferValidityDatesValid",
isOfferValidityDatesValid
);
-Yup.addMethod(Yup.mixed, "isItBeforeNow", isItBeforeNow);
+Yup.addMethod>>(
+ Yup.array,
+ "isItBeforeNow",
+ isItBeforeNow
+);
Yup.addMethod(
Yup.string,
"disputePeriodValue",
diff --git a/src/lib/validation/isItBeforeNow.ts b/src/lib/validation/isItBeforeNow.ts
index 0698fe25d..d0feb143b 100644
--- a/src/lib/validation/isItBeforeNow.ts
+++ b/src/lib/validation/isItBeforeNow.ts
@@ -3,6 +3,9 @@ import dayjs from "dayjs";
function isItBeforeNow() {
return this.test("isItBeforeNow", function (value: (Dayjs | null)[]) {
+ if (!value) {
+ return false;
+ }
const startBeforeNow =
value[0] instanceof dayjs
? value[0]?.isBefore(dayjs())
diff --git a/src/lib/validation/isOfferValidityDatesValid.ts b/src/lib/validation/isOfferValidityDatesValid.ts
index 3fe313e06..e1b471d7b 100644
--- a/src/lib/validation/isOfferValidityDatesValid.ts
+++ b/src/lib/validation/isOfferValidityDatesValid.ts
@@ -5,6 +5,9 @@ function isOfferValidityDatesValid() {
return this.test(
"isOfferValidityDatesValid",
function (value: (Dayjs | null)[]) {
+ if (!value) {
+ return false;
+ }
const rpValue: (Dayjs | null)[] = this.parent.redemptionPeriod;
const doesItEndBefore =
rpValue[1] instanceof dayjs
diff --git a/src/lib/validation/isRedemptionDatesValid.ts b/src/lib/validation/isRedemptionDatesValid.ts
index 6b798638d..76c55bf83 100644
--- a/src/lib/validation/isRedemptionDatesValid.ts
+++ b/src/lib/validation/isRedemptionDatesValid.ts
@@ -3,8 +3,11 @@ import dayjs from "dayjs";
function isRedemptionDatesValid() {
return this.test(
- "isOfferValidityDatesValid",
+ "isRedemptionDatesValid",
function (value: (Dayjs | null)[]) {
+ if (!value) {
+ return false;
+ }
const ovValue = this.parent.offerValidityPeriod;
const doesItEndBefore =
value[1] instanceof dayjs
diff --git a/src/pages/chat/ChatProvider/ChatContext.ts b/src/pages/chat/ChatProvider/ChatContext.ts
index a544db8ff..2456a12fe 100644
--- a/src/pages/chat/ChatProvider/ChatContext.ts
+++ b/src/pages/chat/ChatProvider/ChatContext.ts
@@ -5,10 +5,12 @@ export const Context = createContext<{
bosonXmtp: BosonXmtpClient | undefined;
initialize: Dispatch>;
envName: string;
+ error: unknown;
isInitializing: boolean;
}>({
bosonXmtp: undefined,
initialize: () => console.log("initialize has not been defined"),
+ error: null,
envName: "",
isInitializing: false
});
diff --git a/src/pages/chat/ChatProvider/ChatProvider.tsx b/src/pages/chat/ChatProvider/ChatProvider.tsx
index 11bfee8e6..248262568 100644
--- a/src/pages/chat/ChatProvider/ChatProvider.tsx
+++ b/src/pages/chat/ChatProvider/ChatProvider.tsx
@@ -14,6 +14,7 @@ export default function ChatProvider({ children }: Props) {
const { data: signer } = useSigner();
const [initialize, setInitialized] = useState(0);
const [isLoading, setLoading] = useState(false);
+ const [error, setError] = useState();
const [bosonXmtp, setBosonXmtp] = useState();
useEffect(() => {
if (signer && initialize && !bosonXmtp) {
@@ -25,8 +26,12 @@ export default function ChatProvider({ children }: Props) {
)
.then((bosonClient) => {
setBosonXmtp(bosonClient);
+ setError(null);
+ })
+ .catch((error) => {
+ console.error(error);
+ setError(error);
})
- .catch(console.error)
.finally(() => setLoading(false));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -38,6 +43,7 @@ export default function ChatProvider({ children }: Props) {
initialize: () => {
setInitialized((prev) => prev + 1);
},
+ error,
envName,
isInitializing: isLoading
}}
diff --git a/src/pages/chat/components/ExchangeSidePreview.tsx b/src/pages/chat/components/ExchangeSidePreview.tsx
index 9651d24a2..d00d8f9a8 100644
--- a/src/pages/chat/components/ExchangeSidePreview.tsx
+++ b/src/pages/chat/components/ExchangeSidePreview.tsx
@@ -418,7 +418,7 @@ export default function ExchangeSidePreview({
- {isInDispute && iAmTheBuyer && !isEscalated && !isRetracted ? (
+ {isInDispute && iAmTheBuyer && !isRetracted ? (
Retract
-
- showModal(
- "ESCALATE_MODAL",
- {
- title: "Escalate",
- exchange: exchange,
- refetch: refetchItAll
- },
- "l"
- )
- }
- >
- Escalate
-
+ {!isEscalated ? (
+
+ showModal(
+ "ESCALATE_MODAL",
+ {
+ title: "Escalate",
+ exchange: exchange,
+ refetch: refetchItAll
+ },
+ "l"
+ )
+ }
+ >
+ Escalate
+
+ ) : (
+ <>>
+ )}
) : isInRedeemed && iAmTheBuyer ? (
diff --git a/src/pages/create-product/CreateProduct.tsx b/src/pages/create-product/CreateProduct.tsx
index 83ec0f0fa..259136338 100644
--- a/src/pages/create-product/CreateProduct.tsx
+++ b/src/pages/create-product/CreateProduct.tsx
@@ -24,12 +24,21 @@ function CreateProduct() {
const showCreateProductDraftModal = useCallback(() => {
if (store.shouldDisplayModal) {
- showModal(modalTypes.CREATE_PRODUCT_DRAFT, {
- title: "Draft",
- chooseNew,
- chooseDraft,
- closable: false
- });
+ showModal(
+ modalTypes.CREATE_PRODUCT_DRAFT,
+ {
+ title: "Draft",
+ chooseNew,
+ chooseDraft,
+ closable: false
+ },
+ "auto",
+ undefined,
+ {
+ xs: "100%",
+ s: "31.25rem"
+ }
+ );
} else {
setDraftModalClosed(true);
}
diff --git a/src/pages/create-product/CreateProductInner.tsx b/src/pages/create-product/CreateProductInner.tsx
index 914ca4436..b64336d43 100644
--- a/src/pages/create-product/CreateProductInner.tsx
+++ b/src/pages/create-product/CreateProductInner.tsx
@@ -8,7 +8,6 @@ import {
subgraph
} from "@bosonprotocol/react-kit";
import { parseUnits } from "@ethersproject/units";
-import type { Dayjs } from "dayjs";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { Form, Formik, FormikHelpers, FormikProps } from "formik";
@@ -21,13 +20,11 @@ import { generatePath, useLocation, useNavigate } from "react-router-dom";
import uuid from "react-uuid";
import { useAccount } from "wagmi";
dayjs.extend(localizedFormat);
-
import { BigNumber, ethers } from "ethers";
import { useEffect } from "react";
import { Token } from "../../components/convertion-rate/ConvertionRateContext";
import { FileProps } from "../../components/form/Upload/WithUploadToIpfs";
-import { authTokenTypes } from "../../components/modal/components/CreateProfile/Lens/const";
import {
getLensCoverPictureUrl,
getLensProfilePictureUrl,
@@ -51,7 +48,7 @@ import { ProductRoutes } from "../../lib/routing/routes";
import { fetchIpfsBase64Media } from "../../lib/utils/base64";
import { useChatStatus } from "../../lib/utils/hooks/chat/useChatStatus";
import { Profile } from "../../lib/utils/hooks/lens/graphql/generated";
-import { useAddPendingTransaction } from "../../lib/utils/hooks/transactions/usePendingTransactions";
+import { useCreateOffers } from "../../lib/utils/hooks/offer/useCreateOffers";
import { useCurrentSellers } from "../../lib/utils/hooks/useCurrentSellers";
import { useIpfsStorage } from "../../lib/utils/hooks/useIpfsStorage";
import { useKeepQueryParamsNavigate } from "../../lib/utils/hooks/useKeepQueryParamsNavigate";
@@ -66,8 +63,7 @@ import {
MultiStepsContainer,
ProductLayoutContainer
} from "./CreateProductInner.styles";
-import { createProductSteps, FIRST_STEP, poll } from "./utils";
-import { buildCondition } from "./utils/buildCondition";
+import { createProductSteps, FIRST_STEP } from "./utils";
import { validateDates } from "./utils/dataValidator";
import { CreateProductSteps } from "./utils/index";
@@ -394,7 +390,7 @@ function CreateProductInner({
[history, location, setCurrentStep]
);
- const onCreateNewProject = () => {
+ const onCreateNew = () => {
hideModal();
setCurrentStepWithHistory(FIRST_STEP);
setIsPreviewVisible(false);
@@ -415,10 +411,7 @@ function CreateProductInner({
const { address } = useAccount();
const { sellers, lens: lensProfiles } = useCurrentSellers();
- const addPendingTransaction = useAddPendingTransaction();
-
- const hasSellerAccount = !!sellers?.length;
-
+ const { mutateAsync: createOffers } = useCreateOffers();
const currentOperator = sellers.find((seller) => {
return seller?.operator.toLowerCase() === address?.toLowerCase();
});
@@ -482,7 +475,7 @@ function CreateProductInner({
},
hasMultipleVariants: !!values.productVariants.variants.length,
// these are the ones that we already had before
- onCreateNewProject: onCreateNewProject,
+ onCreateNew: onCreateNew,
onViewMyItem: () => onViewMyItem(metadataInfo.product?.uuid)
},
"auto"
@@ -872,330 +865,47 @@ function CreateProductInner({
});
offersToCreate.push(offerData);
}
-
- showModal("WAITING_FOR_CONFIRMATION");
- const isMetaTx = Boolean(coreSDK.isMetaTxConfigSet && address);
- const seller = address
- ? {
- operator: address,
- admin: address,
- treasury: address,
- clerk: address,
- contractUri: "ipfs://sample",
- royaltyPercentage: "0",
- authTokenId: "0",
- authTokenType: authTokenTypes.NONE
- }
- : null;
const isTokenGated = commonTermsOfSale.tokenGatedOffer.value === "true";
- let txResponse;
- if (isMultiVariant) {
- if (!hasSellerAccount && seller) {
- if (isMetaTx) {
- // createSeller with meta-transaction
- const nonce = Date.now();
- const { r, s, v, functionName, functionSignature } =
- await coreSDK.signMetaTxCreateSeller({
- createSellerArgs: seller,
- nonce
- });
- txResponse = await coreSDK.relayMetaTransaction({
- functionName,
- functionSignature,
- sigR: r,
- sigS: s,
- sigV: v,
- nonce
- });
- } else {
- txResponse = await coreSDK.createSeller(seller);
- }
- showModal("TRANSACTION_SUBMITTED", {
- action: "Create seller",
- txHash: txResponse.hash
- });
- addPendingTransaction({
- type: subgraph.EventType.SellerCreated,
- hash: txResponse.hash,
- isMetaTx,
- accountType: "Seller"
- });
- await txResponse.wait();
- showModal("WAITING_FOR_CONFIRMATION");
- }
- if (isMetaTx) {
- // createOfferBatch with meta-transaction
- const nonce = Date.now();
- const { r, s, v, functionName, functionSignature } =
- await coreSDK.signMetaTxCreateOfferBatch({
- createOffersArgs: offersToCreate,
- nonce
- });
- txResponse = await coreSDK.relayMetaTransaction({
- functionName,
- functionSignature,
- sigR: r,
- sigS: s,
- sigV: v,
- nonce
- });
- } else {
- txResponse = await coreSDK.createOfferBatch(offersToCreate);
- }
- showModal("TRANSACTION_SUBMITTED", {
- action: "Create offer with variants",
- txHash: txResponse.hash
- });
- addPendingTransaction({
- type: subgraph.EventType.OfferCreated,
- hash: txResponse.hash,
- isMetaTx,
- accountType: "Seller"
- });
- const txReceipt = await txResponse.wait();
- const offerIds = coreSDK.getCreatedOfferIdsFromLogs(txReceipt.logs);
-
- if (isTokenGated) {
- showModal("WAITING_FOR_CONFIRMATION");
- if (
- commonTermsOfSale?.tokenContract &&
- commonTermsOfSale.tokenType?.value === TOKEN_TYPES[0].value
- ) {
- try {
- const { decimals: decimalsLocal } =
- await coreSDK.getExchangeTokenInfo(
- commonTermsOfSale.tokenContract
- );
- setDecimals(decimalsLocal);
- } catch (error) {
- setDecimals(undefined);
- }
- }
- const condition = buildCondition(commonTermsOfSale, decimals);
-
- if (isMetaTx) {
- const nonce = Date.now();
- const { r, s, v, functionName, functionSignature } =
- await coreSDK.signMetaTxCreateGroup({
- createGroupArgs: { offerIds, ...condition },
- nonce
- });
- txResponse = await coreSDK.relayMetaTransaction({
- functionName,
- functionSignature,
- sigR: r,
- sigS: s,
- sigV: v,
- nonce
- });
- } else {
- txResponse = await coreSDK.createGroup({ offerIds, ...condition });
- }
- showModal("TRANSACTION_SUBMITTED", {
- action: "Create condition group for offers",
- txHash: txResponse.hash
- });
- await txResponse.wait();
- }
- let createdOffers: OfferFieldsFragment[] | null = null;
- await poll(
- async () => {
- createdOffers = (
- await Promise.all(
- offerIds.map((offerId) =>
- coreSDK.getOfferById(offerId as string)
- )
- )
- ).filter((offer) => !!offer);
- return createdOffers;
- },
- (offers) => {
- return offers.length !== offerIds.length;
- },
- 500
- );
- const [firstOffer] = createdOffers as unknown as OfferFieldsFragment[];
- toast((t) => (
- {
- handleOpenSuccessModal({
- offerInfo: firstOffer || ({} as subgraph.OfferFieldsFragment),
- values
- });
- }}
- />
- ));
- } else {
- const [offerData] = offersToCreate;
- if (isMetaTx) {
- // meta-transaction
- if (!hasSellerAccount && seller) {
- // createSeller with meta-transaction
- const nonce = Date.now();
- const { r, s, v, functionName, functionSignature } =
- await coreSDK.signMetaTxCreateSeller({
- createSellerArgs: seller,
- nonce
- });
- const createSellerResponse = await coreSDK.relayMetaTransaction({
- functionName,
- functionSignature,
- sigR: r,
- sigS: s,
- sigV: v,
- nonce
- });
- showModal("TRANSACTION_SUBMITTED", {
- action: "Create seller",
- txHash: createSellerResponse.hash
- });
- addPendingTransaction({
- type: subgraph.EventType.SellerCreated,
- hash: createSellerResponse.hash,
- isMetaTx,
- accountType: "Seller"
- });
- await createSellerResponse.wait();
- showModal("WAITING_FOR_CONFIRMATION");
- }
- // createOffer with meta-transaction
- const nonce = Date.now();
- if (!isTokenGated) {
- const { r, s, v, functionName, functionSignature } =
- await coreSDK.signMetaTxCreateOffer({
- createOfferArgs: offerData,
- nonce
- });
- txResponse = await coreSDK.relayMetaTransaction({
- functionName,
- functionSignature,
- sigR: r,
- sigS: s,
- sigV: v,
- nonce
- });
- } else {
- if (
- commonTermsOfSale?.tokenContract &&
- commonTermsOfSale.tokenType?.value === TOKEN_TYPES[0].value
- ) {
- try {
- const { decimals: decimalsLocal } =
- await coreSDK.getExchangeTokenInfo(
- commonTermsOfSale.tokenContract
- );
- setDecimals(decimalsLocal);
- } catch (error) {
- setDecimals(undefined);
- }
- }
- const condition = buildCondition(commonTermsOfSale, decimals);
- const { r, s, v, functionName, functionSignature } =
- await coreSDK.signMetaTxCreateOfferWithCondition({
- offerToCreate: offerData,
- condition,
- nonce
- });
- txResponse = await coreSDK.relayMetaTransaction({
- functionName,
- functionSignature,
- sigR: r,
- sigS: s,
- sigV: v,
- nonce
- });
- }
- } else {
- if (isTokenGated) {
- if (
- commonTermsOfSale?.tokenContract &&
- commonTermsOfSale.tokenType?.value === TOKEN_TYPES[0].value
- ) {
- try {
- const { decimals: decimalsLocal } =
- await coreSDK.getExchangeTokenInfo(
- commonTermsOfSale.tokenContract
- );
-
- setDecimals(decimalsLocal);
- } catch (error) {
- setDecimals(undefined);
- }
- }
- const condition = buildCondition(commonTermsOfSale, decimals);
- txResponse =
- !hasSellerAccount && seller
- ? await coreSDK.createSellerAndOfferWithCondition(
- seller,
- offerData,
- condition
- )
- : await coreSDK.createOfferWithCondition(offerData, condition);
- } else {
- txResponse =
- !hasSellerAccount && seller
- ? await coreSDK.createSellerAndOffer(seller, offerData)
- : await coreSDK.createOffer(offerData);
- }
- }
- showModal("TRANSACTION_SUBMITTED", {
- action: "Create offer",
- txHash: txResponse.hash
- });
-
- addPendingTransaction({
- type: subgraph.EventType.OfferCreated,
- hash: txResponse.hash,
- isMetaTx,
- accountType: "Seller"
- });
-
- if (!hasSellerAccount && seller) {
- addPendingTransaction({
- type: subgraph.EventType.SellerCreated,
- hash: txResponse.hash,
- isMetaTx,
- accountType: "Seller"
- });
- }
-
- const txReceipt = await txResponse.wait();
- const offerId = coreSDK.getCreatedOfferIdFromLogs(txReceipt.logs);
- let createdOffer: OfferFieldsFragment | null = null;
- await poll(
- async () => {
- createdOffer = await coreSDK.getOfferById(offerId as string);
- return createdOffer;
- },
- (offer) => {
- return !offer;
- },
- 500
- );
- if (!createdOffer) {
- return;
+ await createOffers({
+ isMultiVariant,
+ offersToCreate,
+ tokenGatedInfo: isTokenGated ? commonTermsOfSale : null,
+ conditionDecimals: decimals,
+ onGetExchangeTokenDecimals: setDecimals,
+ onCreatedOffersWithVariants: ({ firstOffer }) => {
+ toast((t) => (
+ {
+ handleOpenSuccessModal({
+ offerInfo: firstOffer || ({} as subgraph.OfferFieldsFragment),
+ values
+ });
+ }}
+ />
+ ));
+ },
+ onCreatedSingleOffers: ({ offer: createdOffer }) => {
+ toast((t) => (
+ {
+ handleOpenSuccessModal({
+ offerInfo:
+ createdOffer || ({} as subgraph.OfferFieldsFragment),
+ values
+ });
+ }}
+ />
+ ));
}
- toast((t) => (
- {
- handleOpenSuccessModal({
- offerInfo: createdOffer || ({} as subgraph.OfferFieldsFragment),
- values
- });
- }}
- />
- ));
- }
-
- hideModal();
+ });
} catch (error: any) {
// TODO: FAILURE MODAL
console.error("error->", error.errors ?? error);
- showModal("CONFIRMATION_FAILED");
+ showModal("TRANSACTION_FAILED");
}
};
@@ -1221,11 +931,11 @@ function CreateProductInner({
[coreTermsOfSaleKey]: {
...values[coreTermsOfSaleKey],
redemptionPeriod:
- values?.[coreTermsOfSaleKey]?.redemptionPeriod?.map((d: Dayjs) =>
+ values?.[coreTermsOfSaleKey]?.redemptionPeriod?.map((d) =>
dayjs(d).format()
) ?? [],
offerValidityPeriod:
- values?.[coreTermsOfSaleKey]?.offerValidityPeriod?.map((d: Dayjs) =>
+ values?.[coreTermsOfSaleKey]?.offerValidityPeriod?.map((d) =>
dayjs(d).format()
) ?? []
}
diff --git a/src/pages/create-product/utils/buildCondition.ts b/src/pages/create-product/utils/buildCondition.ts
index 508994bf0..24e2fab9a 100644
--- a/src/pages/create-product/utils/buildCondition.ts
+++ b/src/pages/create-product/utils/buildCondition.ts
@@ -7,10 +7,22 @@ import { utils } from "ethers";
import { CreateProductForm } from "../../../components/product/utils";
+type JointTermsOfSale =
+ | CreateProductForm["coreTermsOfSale"]
+ | CreateProductForm["variantsCoreTermsOfSale"];
+
+export type CommonTermsOfSale = Pick<
+ JointTermsOfSale,
+ | "tokenId"
+ | "minBalance"
+ | "tokenType"
+ | "tokenCriteria"
+ | "tokenContract"
+ | "maxCommits"
+>;
+
export const buildCondition = (
- commonTermsOfSale:
- | CreateProductForm["coreTermsOfSale"]
- | CreateProductForm["variantsCoreTermsOfSale"],
+ commonTermsOfSale: CommonTermsOfSale,
decimals?: number
): ConditionStruct => {
let tokenType: TokenType = TokenType.FungibleToken;
diff --git a/src/pages/create-product/utils/dataValidator.ts b/src/pages/create-product/utils/dataValidator.ts
index 8d093edce..fb37321f4 100644
--- a/src/pages/create-product/utils/dataValidator.ts
+++ b/src/pages/create-product/utils/dataValidator.ts
@@ -1,3 +1,5 @@
+import type { Dayjs } from "dayjs";
+
interface ReturnValues {
validFromDateInMS: number;
validUntilDateInMS: number;
@@ -8,34 +10,30 @@ export const validateDates = ({
offerValidityPeriod,
redemptionPeriod
}: {
- offerValidityPeriod: Array<{ $d: string }>;
- redemptionPeriod: Array<{ $d: string }>;
+ offerValidityPeriod: Array;
+ redemptionPeriod: Array;
}): ReturnValues => {
const now = Date.now();
const numberMinutesAdd = 5;
- let validFromDateInMS = Date.parse(offerValidityPeriod[0].$d);
-
+ let validFromDateInMS = offerValidityPeriod[0].toDate().getTime();
if (validFromDateInMS < now) {
validFromDateInMS = new Date(now + numberMinutesAdd * 60000).getTime();
}
- let validUntilDateInMS = Date.parse(offerValidityPeriod[1].$d);
-
+ let validUntilDateInMS = offerValidityPeriod[1].toDate().getTime();
if (validUntilDateInMS < now) {
validUntilDateInMS = new Date(now + numberMinutesAdd * 2 * 60000).getTime();
}
- let voucherRedeemableFromDateInMS = Date.parse(redemptionPeriod[0].$d);
-
+ let voucherRedeemableFromDateInMS = redemptionPeriod[0].toDate().getTime();
if (voucherRedeemableFromDateInMS < now) {
voucherRedeemableFromDateInMS = new Date(
now + numberMinutesAdd * 60000
).getTime();
}
- let voucherRedeemableUntilDateInMS = Date.parse(redemptionPeriod[1].$d);
-
+ let voucherRedeemableUntilDateInMS = redemptionPeriod[1].toDate().getTime();
if (voucherRedeemableUntilDateInMS < now) {
voucherRedeemableUntilDateInMS = new Date(
now + numberMinutesAdd * 2 * 60000
diff --git a/src/pages/create-product/utils/index.tsx b/src/pages/create-product/utils/index.tsx
index 46cd56709..32773d878 100644
--- a/src/pages/create-product/utils/index.tsx
+++ b/src/pages/create-product/utils/index.tsx
@@ -1,7 +1,7 @@
import React from "react";
import ConfirmProductDetails from "../../../components/product/ConfirmProductDetails";
-import CoreTermsOfSale from "../../../components/product/CoreTermsOfSale";
+import CoreTermsOfSale from "../../../components/product/coreTermsOfSale/CoreTermsOfSale";
import ProductImages from "../../../components/product/ProductImages";
import ProductInformation from "../../../components/product/ProductInformation";
import ProductType from "../../../components/product/ProductType";
diff --git a/src/pages/custom-store/store-fields.ts b/src/pages/custom-store/store-fields.ts
index dd9a16a37..51066127c 100644
--- a/src/pages/custom-store/store-fields.ts
+++ b/src/pages/custom-store/store-fields.ts
@@ -190,6 +190,10 @@ export const formModel = {
{
label: "Barlow",
value: "barlow" // defined in src/lib/styles/GlobalStyle.tsx
+ },
+ {
+ label: "Neuropolitical",
+ value: "neuropolitical_rg" // defined in src/lib/styles/GlobalStyle.tsx
}
]
},
diff --git a/src/pages/dispute-centre/DisputeCentre.tsx b/src/pages/dispute-centre/DisputeCentre.tsx
index a8dc4f813..a2978dff4 100644
--- a/src/pages/dispute-centre/DisputeCentre.tsx
+++ b/src/pages/dispute-centre/DisputeCentre.tsx
@@ -303,7 +303,7 @@ function DisputeCentre() {
(error as unknown as { code: string }).code ===
"ACTION_REJECTED";
if (hasUserRejectedTx) {
- showModal("CONFIRMATION_FAILED");
+ showModal("TRANSACTION_FAILED");
}
setSubmitError(error as Error);
diff --git a/src/pages/profile/seller/SellerSocial.tsx b/src/pages/profile/seller/SellerSocial.tsx
index eab5eb813..706e45e02 100644
--- a/src/pages/profile/seller/SellerSocial.tsx
+++ b/src/pages/profile/seller/SellerSocial.tsx
@@ -7,6 +7,7 @@ import {
Profile,
ProfileFieldsFragment
} from "../../../lib/utils/hooks/lens/graphql/generated";
+import { sanitizeUrl } from "../../../lib/utils/url";
import { preAppendHttps } from "../../../lib/validation/regex/url";
import {
DetailShareWrapper,
@@ -26,7 +27,12 @@ function RenderSocial({
icon: Icon
}: RenderSocialProps) {
return (
-
+
{Icon ? Icon : }
);
@@ -60,7 +66,7 @@ export default function SellerSocial({
{/* TODO: Removed as we don't have discord in lens profile */}
{/* */}
{lensUrl !== false && (
- } href={lensUrl} />
+ } href={sanitizeUrl(lensUrl)} />
)}