Embed with React
The SDK's React components render Yutai's four embed elements on a page built with React, each component's props named for the attributes its element reads. Install the package, import the component you need, and the samples below show the result.
The script
Yutai serves the SDK's script at the address below: a page built with React does not load it, because the components' import registers the same elements before the first render.
The script is served today.
<script src="https://yutai.com/sdk/v1/yutai-sdk-web.min.js"></script>The components
Install the distributor SDK package (@yutai/sdk-web) with your package manager, then import the components you need from its react door (@yutai/sdk-web/react). The import registers the same elements the script line above registers, before the first render: a React page never writes a define of its own, and it needs no second copy of the SDK.
Each component renders its element, never a second card. The props you pass are written on the element as its own attributes, so the element reads its facts on connect the way it does on a page without React.
The components cover all four of the SDK's elements. The benefits module's two doors, the wallets and the answer, and its claimWallets property stay on the benefits module's own page; its component's onClaimed prop hears the module's own claimed event.
The props
Each component's props are its element's attributes under their camel case names, listed below in the element's own order. A prop you pass is written on the element under the attribute's own name; a prop you leave out writes no attribute, so the element reads it as missing. The attributes' full words and the tokens each element takes stay on the element pages: the credential card, the benefits list, the benefits module and the tier badge.
The credential card's props
tier- Required. The tier the card carries, one of Holder, Steward or Patron.
status- Required. The verification status the card shows: minted or revoked.
tenureDays- With the tenure set, or alone on a Patron card: the days the credential has been held, like "145". The tenure comes as one set: pass tenureDays, tenureNextTier and tenureProgress together, or none of them.
tenureNextTier- With the tenure set: the tier the tenure is moving toward, one of the tiers above the card's own tier. Not given on a Patron card, the top tier.
tenureProgress- With the tenure set: the progress toward the next tier, a percentage of 0 through 100, like "62.5". Not given on a Patron card, the top tier.
tenureProgressDecimals- Optional. The scale the percentage shows: a whole number of digits, like "1". Not given on a Patron card.
The tier badge's props
tier- Required on the tier draw. The tier the badge carries, one of Holder, Steward or Patron. A badge names a tier or an instrument, never both.
tenureDays- Optional, with tier on the tier draw: the days the credential has been held, like "145", the same figure the card's tenureDays carries. Absent, the badge draws the tier's word alone.
isin- Required on the instrument draw. The ISIN of the instrument the badge marks: the badge asks the distributor API which benefits the instrument carries, through the client your page connected with connectDistributorApi, and paints the mark that says benefits exist at the company. The tenureDays prop never rides the instrument draw.
answer- Optional on the instrument draw. The availability read's own answer for the instrument, as JSON text: the badge draws the row it carries instead of asking anyone, so a page whose read happened elsewhere hands every badge the row the read answered it with, and no key reaches the browser. Write a badge only where your read answered; a company the read answers nothing for wears no badge.
The benefits list's props
benefits- Required. The benefit rows as an array, at most 500 rows, each in the shape the benefits list page documents. The wrapper serialises the array to the one benefits attribute the element reads, so a page passes its rows and never a string it builds itself.
The benefits list adds one prop the element's attributes do not carry: onClaim, called with the benefit's id once per claim event the element dispatches. The claim stays your own action: the component writes nothing itself, and the benefits list page carries the event's words.
The benefits module's props
wallets- Optional. The wallet addresses to read, as an array, each once. The wrapper serialises the array to the one wallets attribute, and the element asks through the client your page connected with connectDistributorApi. Pass the wallets or the answer, never both.
answer- Optional. The eligibility answer as JSON text: the element draws the tokens and benefits the answer carries without asking anyone, so a page whose read ran on its own server hands the answer over and no key reaches the browser. Pass the answer or the wallets, never both.
The benefits module's two props are its element's own doors: pass the wallets or the answer, never both. It adds one prop the element's attributes do not carry: onClaimed, called with the claim's id and the benefit's id once per claim the module grants. The component writes nothing itself, and the benefits module page carries the element's own words.
The samples
Each sample below renders through the components above, and its code block pastes whole into a React page: the component imports from the SDK's package, the sample's data stands written out in the block, and on your page you pass the values your holder carries.
The credential card sample
"use client";
import { CredentialCard } from "@yutai/sdk-web/react";
const card = {
"tier": "Holder",
"status": "minted",
"tenureDays": "145",
"tenureNextTier": "Steward",
"tenureProgress": "62.5"
} as const;
export function CredentialCardSample() {
return (
<CredentialCard
tier={card.tier}
status={card.status}
tenureDays={card.tenureDays}
tenureNextTier={card.tenureNextTier}
tenureProgress={card.tenureProgress}
/>
);
}The benefits list sample
"use client";
import { BenefitsList } from "@yutai/sdk-web/react";
const benefits = [
{
"benefitId": "bft_01H8Z2N9P4QX7K3M5A0V8D9T2W",
"name": "Season voucher",
"type": "VOUCHER",
"delivery": "CODE",
"state": "eligible",
"sourceMode": "SIMULATED"
},
{
"benefitId": "bft_01H8Z2N9P4QX7K3M5A0V8D9T2X",
"name": "Lounge access",
"type": "ACCESS",
"delivery": "VENUE_REDEMPTION",
"state": "locked",
"lockedReason": "This benefit opens after 30 days of tenure.",
"sourceMode": "SIMULATED"
},
{
"benefitId": "bft_01H8Z2N9P4QX7K3M5A0V8D9T2Y",
"name": "Welcome points",
"type": "POINTS",
"delivery": "POINTS_CREDIT",
"state": "claimed",
"sourceMode": "SIMULATED"
}
] as const;
export function BenefitsListSample() {
return <BenefitsList benefits={benefits} />;
}The benefits module sample
"use client";
import { BenefitsModule } from "@yutai/sdk-web/react";
const answer = {
"wallets": [
{
"wallet": "0xabc0000000000000000000000000000000000001",
"read": true,
"sourceMode": "SIMULATED",
"tokens": [
{
"issuer": null,
"security": {
"name": "Sample Global Holdings",
"isin": "US0000000009"
},
"wrapper": "Sample token programme",
"chain": "eip155:88880",
"shares": "15",
"daysHeld": 452,
"tier": "Patron",
"benefits": [
{
"benefitId": "bft_01K4V9QG000000000000000001",
"name": "Sample lounge access",
"type": "ACCESS",
"delivery": "VENUE_REDEMPTION",
"state": "eligible",
"illustrative": true
},
{
"benefitId": "bft_01K4V9QG000000000000000002",
"name": "Sample welcome points",
"type": "POINTS",
"delivery": "POINTS_CREDIT",
"state": "locked",
"lockedReason": "This benefit opens after 30 days of tenure.",
"illustrative": true
}
]
}
]
},
{
"wallet": "0xdef0000000000000000000000000000000000002",
"read": false,
"sourceMode": "SIMULATED",
"unreadReason": "Yutai has not read this wallet yet."
}
]
} as const;
export function BenefitsModuleSample() {
return <BenefitsModule answer={JSON.stringify(answer)} />;
}The tier badge sample
"use client";
import { TierBadge, type TierBadgeProps } from "@yutai/sdk-web/react";
const badges: TierBadgeProps[] = [
{
"tier": "Holder",
"tenureDays": "145"
},
{
"tier": "Steward",
"tenureDays": "58"
},
{
"tier": "Patron"
}
];
export function TierBadgeSamples() {
return (
<>
{badges.map((badge) => (
<TierBadge key={badge.tier} tier={badge.tier} tenureDays={badge.tenureDays} />
))}
</>
);
}