Read and evaluate gates
This is the third part of a four-part tutorial series for building a tokengated storefront.
In this tutorial, you'll create a function that evaluates gates on products with your customer's connected wallet. The evaluation function determines if the customer should receive the associated reaction defined in the gate configuration you created in the first tutorial.
What you'll learn
Anchor link to section titled "What you'll learn"In this tutorial, you'll learn how to do the following:
- Read gates bound to a product.
- Use wallet data stored server-side to evaluate gate eligibility.
- Update your
ProductForm
to include theTokengate
component, and display the customer's eligibility to receive the reaction defined in thegateConfiguration
.
Requirements
Anchor link to section titled "Requirements"- You've followed the getting started and saving connected wallet to session storage steps of the tutorial series.
- You've created an Alchemy account and retrieved your Alchemy API key.
Step 1: Update your .env file
Anchor link to section titled "Step 1: Update your .env file"Add a new environment variable named ALCHEMY_API_KEY
to your ENV file. Your ENV file should look similar to the one below:
Step 2: Retrieve product gates
Anchor link to section titled "Step 2: Retrieve product gates"To evaluate gates, you first need to retrieve the gates bound to your products. In this section, you'll make changes to your product query and your loader function to retrieve and parse the gates bound to the product.
Update the product query
Anchor link to section titled "Update the product query"Open your
($locale).products.$productHandle
JSX or TSX file.Near the end of the file, find the
PRODUCT_QUERY
constant.In this query, paste the fields from the code sample below.
You can paste them anywhere within the
product
query field. In the example repository the fields are betweendescription
andoptions
.Make sure that you replace the placeholder
headless_gating_example
namespace with your own metafield namespace.
Generate the unstable API schema (TypeScript only)
Anchor link to section titled "Generate the unstable API schema (TypeScript only)"If you're using TypeScript, then you need to generate the types for the unstable
Storefront API schema. Generating the unstable
schema types allows you to assign the correct types to the gateConfiguration
and product
resources.
In a terminal, run the following command to install the packages needed to generate the schema types:
In your project's root folder, create a new file called
codegen.js
.Add the following code:
Generate the
unstable
API schema.Run the following script by using your preferred package manager:
After running the following command, you'll notice a new file added to your project located in
/app/generated/storefront-api-types.ts
.
Update the loader (TypeScript only)
Anchor link to section titled "Update the loader (TypeScript only)"on the $productHandle route to retrieve the stored wallet value.
If you're using TypeScript, then you need to update the loader
function in your $productHandle
route to reference the correct types from the Storefront API schema.
Open your
/app/routes/($locale).products.$productHandle
JSX or TSX file.Add the following import statements:
Update the types for the GraphQL payload in the
loader
function by replacing the query with the following code:
Step 3: Evaluate the gate
Anchor link to section titled "Step 3: Evaluate the gate"In this step, you'll create a server-side function that requests data related to a user's wallet address from Alchemy. The data that you receive from Alchemy is used to evaluate whether a customer should receive the benefits defined in the gate's reaction
.
Add Alchemy response types (TypeScript only)
Anchor link to section titled "Add Alchemy response types (TypeScript only)"If you're using TypeScript, then copy the following type definitions into the bottom of /app/lib/type.ts
:
Add an evaluate gate function
Anchor link to section titled "Add an evaluate gate function"In this step, you'll create functions to do the following:
- Parse the provided
gateConfiguration
for arequirements
definition. - Fetch a collection of owned NFTs for a wallet address.
In your project's
/app/lib
folder, create a new file calledevaluateGate.server.js
, orevaluateGate.server.ts
if you're using TypeScript.Add the following code:
Evaluate gates in the product loader
Anchor link to section titled "Evaluate gates in the product loader"Using the product's gates from the PRODUCT_QUERY
and the wallet stored in session from the previous step, you can now perform gate evaluation.
- Open the
/app/routes/($locale).products.$productHandle
JSX or TSX file. Add the following import statement:
In the same file, update the
loader
by adding the following code:Update the
return
statement of the loader by addinggateConfiguration
,unlockingTokens
, andwallet
to the return statement.
Step 4: Update the product form
Anchor link to section titled "Step 4: Update the product form"Now that the loader is returning gateConfiguration
, unlockingTokens
, and wallet
, update your ProductForm
to display your customer's eligibility, using the Tokengate
component from @shopify/tokengate
.
- Open your
($locale).products.$productHandle
JSX or TSX file. Import the following components:
The
ConnectButton
component from the@shopify/connect-wallet
package.The
Tokengate
component from@shopify/tokengate
package.In the same file, locate the
ProductForm
component, and update the destructured data from theuseLoaderData
to match the following code:Locate the constant named
isOutOfStock
within theProductForm
component.The
Tokengate
component uses a prop namedisSoldOut
, which won't allow ybcibbected wallets to connect when the product is sold out.Paste the following code directly below the
isOutOfStock
constant:Locate the return statement for the
ProductForm
component.Directly above the return statement, paste the following code:
Add the
Tokengate
component to theProductForm
by copying the following code and pasting it into the firstdiv
element of theProductForm
return statement.Directly below the code you pasted into the return statement from the last step, wrap the
ProductOptions
and remaining code with the following:To see a representation of what your code might look like, view the sample repository.