diff --git a/docs/pages/hooks/useCreateNFT.mdx b/docs/pages/hooks/useCreateNFT.mdx index d9d22f92..35698c7a 100644 --- a/docs/pages/hooks/useCreateNFT.mdx +++ b/docs/pages/hooks/useCreateNFT.mdx @@ -27,7 +27,6 @@ export default function Component() { isAnimation: false, // set to true if content file is a video. Require to set preview isPrivate: false, // set to true if content is private. Require to set preview. // optional - isLazyMint: true, // mints the NFT using lazy minting amount: 1, // number of NFT to create. Require Standard.ERC1155 royalties: 10, // royalty amount in percentage preview: azukiImagePreview, // preview in the case of private or animation content uploaded by user @@ -86,7 +85,6 @@ useCreateNFT( preview?: File isAnimation: boolean isPrivate: boolean - isLazyMint: boolean amount?: number royalties?: number traits?: { type: string; value: string }[] @@ -113,7 +111,6 @@ Arguments: preview?: File, // preview in the case of private or animation content uploaded by user isAnimation: boolean, // set to true if content file is a video. Require to set preview isPrivate: boolean, // set to true if content is private. Require to set preview. - isLazyMint: boolean, // set to true if you want the NFT to be lazy minted amount?: number, // number of NFT to create. Require Standard.ERC1155 royalties?: number, // royalty amount in percentage traits?: { type: string, value: string }[] // Array of traits associated to the NFT diff --git a/packages/components/src/Token/Form/Create.tsx b/packages/components/src/Token/Form/Create.tsx index 33e5c05a..f5a06ba2 100644 --- a/packages/components/src/Token/Form/Create.tsx +++ b/packages/components/src/Token/Form/Create.tsx @@ -131,7 +131,6 @@ const TokenFormCreate: FC = ({ amount: multiple ? parseInt(data.amount) : 1, royalties: parseFloat(data.royalties), traits: [{ type: 'Category', value: data.category }], - isLazyMint: activateLazyMint, }) onCreated(assetId) diff --git a/packages/hooks/CHANGELOG.md b/packages/hooks/CHANGELOG.md index 991be8a5..d1b60b18 100644 --- a/packages/hooks/CHANGELOG.md +++ b/packages/hooks/CHANGELOG.md @@ -6,6 +6,13 @@ #### Added +- Add `useConfig` hook to return the configuration of the platform [#65](https://github.com/liteflow-labs/libraries/pull/65) + - `hasLazyMint` is true when lazymint is activated + - `hasReferralSystem` is true when the referral and invitation system is activated + - `hasSocialFeatures` is true when all the social features (likes, comments...) are activated + - `hasTopUp` is true when fiat on ramp is activated + - `hasUnlockableContent` is true when unlockable content is activated + #### Changed #### Deprecated @@ -14,6 +21,8 @@ #### Fixed +- Add proper errors when calling a hook relying on a feature not activated [#65](https://github.com/liteflow-labs/libraries/pull/65) + #### Security ## [v1.0.0-beta.8](https://github.com/liteflow-labs/libraries/releases/tag/v1.0.0-beta.8) - 2022-11-15 diff --git a/packages/hooks/src/context.tsx b/packages/hooks/src/context.tsx index fc8090b7..91b655cb 100644 --- a/packages/hooks/src/context.tsx +++ b/packages/hooks/src/context.tsx @@ -1,4 +1,4 @@ -import { GraphQLClient } from 'graphql-request' +import { gql, GraphQLClient } from 'graphql-request' import React, { createContext, PropsWithChildren, @@ -7,13 +7,26 @@ import React, { useMemo, useState, } from 'react' -import type { Sdk } from './graphql' +import type { Config, Sdk } from './graphql' import { getSdk } from './graphql' +gql` + query GetConfig { + config { + hasLazyMint + hasReferralSystem + hasSocialFeatures + hasTopUp + hasUnlockableContent + } + } +` + export type LiteflowContext = { setAuthenticationToken: (token: string) => void resetAuthenticationToken: () => void sdk: Sdk + config: Promise } export type LiteflowProviderProps = { @@ -28,6 +41,7 @@ export const LiteflowContext = createContext({ throw new Error('not implemented') }, sdk: {} as Sdk, + config: {} as Promise, }) export function LiteflowProvider({ @@ -37,6 +51,10 @@ export function LiteflowProvider({ const [authenticationToken, setAuthenticationToken] = useState() const client = useMemo(() => new GraphQLClient(endpoint), [endpoint]) const sdk = useMemo(() => getSdk(client), [client]) + const config = useMemo( + () => sdk.GetConfig().then(({ config }) => config), + [sdk], + ) const resetAuthenticationToken = useCallback( () => setAuthenticationToken(undefined), @@ -58,6 +76,7 @@ export function LiteflowProvider({ resetAuthenticationToken, setAuthenticationToken, sdk, + config, }} > {children} diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index 7a6de36d..220d1454 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -6,6 +6,7 @@ import useAuctionStatus from './useAuctionStatus' import useAuthenticate from './useAuthenticate' import useBalance from './useBalance' import useCancelOffer, { CancelOfferStep } from './useCancelOffer' +import useConfig from './useConfig' import useCreateAuction from './useCreateAuction' import useCreateNFT, { CreateNftStep } from './useCreateNFT' import useCreateOffer, { CreateOfferStep } from './useCreateOffer' @@ -38,6 +39,7 @@ export { * Stable * These hooks are ready to use and are unlikely to have breaking change */ + useConfig, useAcceptAuction, useAcceptOffer, useAuthenticate, diff --git a/packages/hooks/src/useAddFund.ts b/packages/hooks/src/useAddFund.ts index 1ccda518..ed63bd30 100644 --- a/packages/hooks/src/useAddFund.ts +++ b/packages/hooks/src/useAddFund.ts @@ -3,6 +3,7 @@ import { gql } from 'graphql-request' import { useCallback, useContext, useState } from 'react' import invariant from 'ts-invariant' import { LiteflowContext } from './context' +import useConfig from './useConfig' import { ErrorMessages } from './errorMessages' gql` @@ -19,7 +20,10 @@ export default function useAddFund( ): [() => Promise, { loading: boolean }] { const { sdk } = useContext(LiteflowContext) const [loading, setLoading] = useState(false) + const config = useConfig() + const addFunds = useCallback(async () => { + invariant((await config).hasTopUp, ErrorMessages.FEATURE_DISABLED_TOP_UP) invariant(signer, ErrorMessages.SIGNER_FALSY) try { setLoading(true) @@ -32,6 +36,6 @@ export default function useAddFund( } finally { setLoading(false) } - }, [sdk, signer]) + }, [sdk, signer, config]) return [addFunds, { loading }] } diff --git a/packages/hooks/src/useConfig.ts b/packages/hooks/src/useConfig.ts new file mode 100644 index 00000000..fd68126f --- /dev/null +++ b/packages/hooks/src/useConfig.ts @@ -0,0 +1,8 @@ +import { useContext } from 'react' +import { LiteflowContext } from './context' +import { Config } from './graphql' + +export default function useConfig(): Promise { + const { config } = useContext(LiteflowContext) + return config +} diff --git a/packages/hooks/src/useCreateNFT.ts b/packages/hooks/src/useCreateNFT.ts index c1d4a39a..041e5c78 100644 --- a/packages/hooks/src/useCreateNFT.ts +++ b/packages/hooks/src/useCreateNFT.ts @@ -6,6 +6,7 @@ import { LiteflowContext } from './context' import { ErrorMessages } from './errorMessages' import { Standard } from './graphql' import useCheckOwnership from './useCheckOwnership' +import useConfig from './useConfig' import useIPFSUploader from './useIPFSUploader' import { convertTx } from './utils/transaction' @@ -85,7 +86,6 @@ type createNftFn = (data: { amount?: number royalties?: number traits?: { type: string; value: string }[] - isLazyMint?: boolean }) => Promise export default function useCreateNFT( @@ -99,6 +99,7 @@ export default function useCreateNFT( }, ] { const { sdk } = useContext(LiteflowContext) + const config = useConfig() const [transactionHash, setTransactionHash] = useState() const [activeStep, setActiveProcess] = useState( CreateNftStep.INITIAL, @@ -167,8 +168,11 @@ export default function useCreateNFT( amount, royalties, traits, - isLazyMint, }) => { + invariant( + !isPrivate || (isPrivate && (await config).hasUnlockableContent), + ErrorMessages.FEATURE_DISABLED_UNLOCKABLE_CONTENT, + ) invariant(signer, ErrorMessages.SIGNER_FALSY) const account = await signer.getAddress() @@ -182,7 +186,7 @@ export default function useCreateNFT( }) // lazy minting - if (isLazyMint) { + if ((await config).hasLazyMint) { const assetToCreate = { standard, creatorAddress: account.toLowerCase(), @@ -274,7 +278,7 @@ export default function useCreateNFT( setTransactionHash(undefined) } }, - [sdk, signer, pollOwnership, uploadMedia], + [sdk, signer, pollOwnership, uploadMedia, config], ) return [createNft, { activeStep, transactionHash }] diff --git a/packages/hooks/src/useInvitation.ts b/packages/hooks/src/useInvitation.ts index 7a34cb8b..0b1ab15e 100644 --- a/packages/hooks/src/useInvitation.ts +++ b/packages/hooks/src/useInvitation.ts @@ -3,6 +3,7 @@ import { gql } from 'graphql-request' import { useCallback, useContext, useState } from 'react' import invariant from 'ts-invariant' import { LiteflowContext } from './context' +import useConfig from './useConfig' import { ErrorMessages } from './errorMessages' gql` @@ -40,9 +41,14 @@ export default function useInvitation(signer: Signer | undefined): { creating: boolean } { const { sdk } = useContext(LiteflowContext) + const config = useConfig() const [accepting, setAccepting] = useState(false) const [creating, setCreating] = useState(false) const create = useCallback(async () => { + invariant( + (await config).hasReferralSystem, + ErrorMessages.FEATURE_DISABLED_REFERRAL, + ) invariant(signer, ErrorMessages.SIGNER_FALSY) try { setCreating(true) @@ -61,10 +67,14 @@ export default function useInvitation(signer: Signer | undefined): { } finally { setCreating(false) } - }, [sdk, signer]) + }, [sdk, signer, config]) const accept = useCallback( async (invitationId: string) => { + invariant( + (await config).hasReferralSystem, + ErrorMessages.FEATURE_DISABLED_REFERRAL, + ) try { setAccepting(true) const { acceptInvitation } = await sdk.AcceptInvitation({ @@ -79,7 +89,7 @@ export default function useInvitation(signer: Signer | undefined): { setAccepting(false) } }, - [sdk], + [sdk, config], ) return { create, accept, accepting, creating } diff --git a/packages/templates/CHANGELOG.md b/packages/templates/CHANGELOG.md index 4d52b647..0b2e1559 100644 --- a/packages/templates/CHANGELOG.md +++ b/packages/templates/CHANGELOG.md @@ -4,6 +4,8 @@ #### Breaking Changes +- `AssetForm` template does not require the `activateLazyMint` and `activateUnlockableContent` props anymore [#65](https://github.com/liteflow-labs/libraries/pull/65) + #### Added #### Changed diff --git a/packages/templates/src/asset/Form.tsx b/packages/templates/src/asset/Form.tsx index c4061ef6..76f92cb2 100644 --- a/packages/templates/src/asset/Form.tsx +++ b/packages/templates/src/asset/Form.tsx @@ -18,14 +18,16 @@ import { } from '@nft/components' import type { Props as NFTCardProps } from '@nft/components/dist/Token/Card' import type { FormData } from '@nft/components/dist/Token/Form/Create' -import { useSession } from '@nft/hooks' +import { useConfig, useSession } from '@nft/hooks' import { HiBadgeCheck } from '@react-icons/all-files/hi/HiBadgeCheck' +import { useEffect } from '@storybook/addons' import { GetServerSideProps, NextPage } from 'next' import Trans from 'next-translate/Trans' import useTranslation from 'next-translate/useTranslation' import { useRouter } from 'next/router' import React, { useCallback, useMemo, useState } from 'react' import { + Config, FetchAccountDocument, FetchAccountQuery, useFetchAccountQuery, @@ -75,28 +77,26 @@ export const Template: NextPage< walletConnect: boolean networkName: string } - activateUnlockableContent: boolean maxRoyalties?: number restrictMintToVerifiedAccount?: boolean reportEmail?: string - activateLazyMint?: boolean } > = ({ multiple, explorer, uploadUrl, login, - activateUnlockableContent, traits, currentAccount, maxRoyalties = 30, restrictMintToVerifiedAccount = false, reportEmail, - activateLazyMint = false, }) => { const { t } = useTranslation('templates') const { back, push } = useRouter() const { account, ready, signer } = useSession() + const configPromise = useConfig() + const [config, setConfig] = useState() const toast = useToast() const { data } = useFetchAccountQuery({ variables: { @@ -158,6 +158,11 @@ export const Template: NextPage< [push, t, toast], ) + useEffect(() => { + void configPromise.then(setConfig) + return () => setConfig(undefined) + }, [configPromise]) + if (restrictMintToVerifiedAccount && !creator.verified) { return ( <> @@ -235,9 +240,9 @@ export const Template: NextPage< onCreated={onCreated} onInputChange={setFormData} login={login} - activateUnlockableContent={activateUnlockableContent} + activateUnlockableContent={config?.hasUnlockableContent || false} maxRoyalties={maxRoyalties} - activateLazyMint={activateLazyMint} + activateLazyMint={config?.hasLazyMint || false} />