fansunited-frontend-components
v0.0.39-RC2
Published
Various user centric components for Fans United features
Readme
Fans United Frontend Components
A collection of interactive components for Fans United widgets providing engaging experiences and tools.
Installation
npm install fansunited-frontend-components fansunited-frontend-coreyarn add fansunited-frontend-components fansunited-frontend-coreNote: Both packages are required.
fansunited-frontend-coreprovides types and utilities, whilefansunited-frontend-componentsprovides the UI components.
Quick Start
import React from "react";
import { ClassicQuizPlay } from "fansunited-frontend-components";
import { ClassicQuizPlayProps, WidgetTemplate } from "fansunited-frontend-core";
import { FansUnitedSDK } from "fansunited-sdk-esm";
const sdk = FansUnitedSDK({
// your config here
});
const App: React.FC = () => {
const props: ClassicQuizPlayProps = {
entityId: "your-quiz-id",
sdk,
template: WidgetTemplate.STANDARD, // Also SPLIT and OVERLAY templates are available
language: "en", // "bg" | "en" | "ro" | "pt" | "sr" | "fr" | "de" | "it" | "fr-be" | "fr" | "pl" | "pt" | "pt-br" | "sk
};
return (
<div>
<h1>My App</h1>
<ClassicQuizPlay {...props} />
</div>
);
};
export default App;Components
ClassicQuizPlay
Interactive quiz component with multiple templates and customization options.
Required Props
| Prop | Type | Description |
| ---------- | -------------------- | ----------------------- |
| entityId | string | Classic Quiz identifier |
| sdk | FansUnitedSDKModel | SDK instance |
| template | WidgetTemplate | Layout template |
| language | LanguageType | Display language |
Optional Props
| Prop | Type | Description |
| ---------------------------- | ----------------------- | ------------------------------------------- |
| themeOptions | CustomThemeOptions | Theme configuration |
| showAnswerExplanations | boolean | Show explanations after quiz completion |
| leads | LeadsOptions | Lead collection settings |
| imagePosition | "left" \| "right" | Image position (STANDARD template only) |
| defaultImagePlaceholderUrl | string | URL for default image placeholder |
| userIsLoggedIn | boolean | Determine if the user is logged in |
| signInCTA | SignInCTADetails | Sign in call to action button configuration |
| additionalCTA | AdditionalCTADetails | Additional call to action button configuration |
| rulesDisplay | RulesDisplay | Game rules display configuration |
Templates
import { WidgetTemplate, ClassicQuizPlayProps } from "fansunited-frontend-core";
// Standard template with optional image positioning
const standardProps: ClassicQuizPlayProps = {
template: WidgetTemplate.STANDARD,
imagePosition: "left", // or 'right'
// ... other props
};
// Other templates
const overlayProps: ClassicQuizPlayProps = {
template: WidgetTemplate.OVERLAY, // WidgetTemplate.SPLIT
// imagePosition not available for non-standard templates
// ... other props
};Theming
Customize the appearance using theme options:
import { CustomThemeOptions } from "fansunited-frontend-core";
// Default theme options
const themeOptions: CustomThemeOptions = {
mode: "light", // or 'dark'
colorSchemes: {
light: {
palette: {
success: {
plainColor: "#4CAF50",
outlinedBorder: "#4CAF50",
softBg: "#E3FBE3",
},
danger: {
softBg: "#FEE4E2",
plainColor: "#F44336",
outlinedBorder: "#F44336",
},
primary: {
plainColor: "#1A77D2",
outlinedBorder: "#1A77D2",
onPrimary: "#FAFAFA",
primaryContainer: "#2397F3",
},
warning: {
softBg: "#FEF0C7",
plainColor: "#DC6803",
},
},
textPrimary: "#212121",
textSecondary: "#212121",
textBody: "#424242",
textColor: "#212121",
textDisabled: "#212121",
surface: "#FFFFFF",
onSurface: "#F5F5F5",
surfaceVariant: "#EEEEEE",
surfaceTintDim: "#212121",
surfaceInverse: "#F5F5F5",
outlineEnabledBorder: "#E0E0E0",
secondaryContainer: "#BDBDBD",
},
dark: {
palette: {
primary: {
plainColor: "#1A77D2",
outlinedBorder: "#1A77D2",
onPrimary: "#FAFAFA",
primaryContainer: "#2397F3",
},
success: {
plainColor: "#4CAF50",
outlinedBorder: "#4CAF50",
softBg: "#042F04",
},
danger: {
softBg: "#430A0A",
plainColor: "#F44336",
outlinedBorder: "#F44336",
},
warning: {
softBg: "#FEF0C7",
plainColor: "#DC6803",
},
},
textPrimary: "#FAFAFA",
textSecondary: "#FAFAFA",
textBody: "#FAFAFA",
textColor: "#FAFAFA",
textDisabled: "#FAFAFA",
surface: "#424242",
onSurface: "#212121",
surfaceVariant: "#616161",
surfaceTintDim: "#FAFAFA",
surfaceInverse: "#FAFAFA",
outlineEnabledBorder: "#757575",
secondaryContainer: "#757575",
},
},
customBreakpoints: {
values: {
xs: 0,
sm: 444,
md: 600,
lg: 900,
xl: 1200,
xxl: 1536,
},
},
spacingScale: {
"3xs": "2px",
"2xs": "4px",
xs: "8px",
sm: "12px",
md: "16px",
lg: "24px",
xl: "32px",
"2xl": "40px",
"3xl": "48px",
},
customFontFamily: {
light: {
primary: "Ubuntu, sans-serif",
secondary: "Roboto, sans-serif",
},
dark: {
primary: "Ubuntu, sans-serif",
secondary: "Roboto, sans-serif",
},
},
customRadius: {
light: {
none: "0px",
"2xs": "2px",
xs: "4px",
sm: "8px",
md: "12px",
lg: "16px",
xl: "24px",
"2xl": "232px",
full: "1000px",
},
dark: {
none: "0px",
"2xs": "2px",
xs: "4px",
sm: "8px",
md: "12px",
lg: "16px",
xl: "24px",
"2xl": "232px",
full: "1000px",
},
},
border: {
light: {
size: "1px",
},
dark: {
size: "2px",
},
},
imageBackgroundGradient: {
light: {
standard:
"linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, rgba(18, 18, 18, 0.8) 100%)",
split:
"linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, rgba(18, 18, 18, 0.8) 100%)",
},
dark: {
standard:
"linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, rgba(18, 18, 18, 0.8) 100%)",
split:
"linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, rgba(18, 18, 18, 0.8) 100%)",
overlay:
"linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, rgba(18, 18, 18, 0.8) 100%)",
},
},
};
<ClassicQuizPlay {...otherProps} themeOptions={themeOptions} />;Lead Collection
Enable lead capture functionality:
import { LeadsOptions } from "fansunited-frontend-core";
const leads: LeadsOptions = {
position: "before", // "before" | "after"
fields: ["fullName"], // Available: "fullName" | "firstName" | "lastName" | "email" | "gender" | "country" | "phoneCountryCode" | "phoneNumber"
campaignId: "test-quizzes",
campaignName: "Test Quizzes",
phoneCountryCode: "359", // When not provided will set the phone country code from component language prop. So for example if the language is "bg" and phoneCountryCode is not provided, it will fallback to "359"
syncWithProfile: true, // Optional: sync form data to user profile after successful submission
};
<ClassicQuizPlay {...otherProps} leads={leads} />;Sign in Configuration
Control user authentication and sign-in behavior using the userIsLoggedIn and signInCTA props.
import { SignInCTADetails } from "fansunited-frontend-core";
// Basic sign-in with onClick handler
const signInCTA: SignInCTADetails = {
defaultLabel: "Sign In",
onClick: () => {
// Handle sign-in logic
console.log("Sign in clicked");
},
};
// Sign-in with URL navigation
const signInCTA: SignInCTADetails = {
defaultLabel: "Login",
url: "https://your-auth-provider.com/login",
target: "_blank", // or "_self"
};
// Custom sign-in component
const signInCTA: SignInCTADetails = {
component: <CustomSignInButton />,
};
<ClassicQuizPlay
{...otherProps}
userIsLoggedIn={false}
signInCTA={signInCTA}
/>;Sign-in Priority Order:
- Custom Component - If
signInCTA.componentis provided, it will be rendered - Click Handler - If
signInCTA.onClickis provided, a button with the handler will be rendered - URL Navigation - If
signInCTA.urlis provided, a button will be rendered and clicking will navigate to the URL - Disabled - If no
signInCTAis provided, a disabled button will be shown
Behavior:
- When
userIsLoggedInisfalseand the quiz requires authentication (authRequirement: "REGISTERED"), the sign-in screen will be displayed instead of the quiz
Additional CTA Configuration
Add an extra call-to-action button to the quiz completion screen using the additionalCTA prop.
import { AdditionalCTADetails } from "fansunited-frontend-core";
// Custom component
const additionalCTA: AdditionalCTADetails = {
component: <CustomCTAButton />,
};
// Basic CTA with onClick handler
const additionalCTA: AdditionalCTADetails = {
defaultLabel: "See More",
onClick: () => {
// Handle click logic
console.log("Additional CTA clicked");
},
};
// CTA with URL navigation
const additionalCTA: AdditionalCTADetails = {
defaultLabel: "Visit Website",
url: "https://your-website.com",
target: "_blank", // or "_self"
};
<ClassicQuizPlay
{...otherProps}
additionalCTA={additionalCTA}
/>;Priority Order:
- Custom Component - If
additionalCTA.componentis provided, it will be rendered - Click Handler - If
additionalCTA.onClickis provided, a button with the handler will be rendered - URL Navigation - If
additionalCTA.urlis provided, a button will be rendered and clicking will navigate to the URL
Placement:
- Standard variant: Displayed after "Play Again" and "Share Result" buttons
- Split variant: Displayed after "Play Again" button in the thank you container
- Overlay variant: Displayed after "Play Again" and "Share Result" buttons
Rules Display Configuration
Display game rules and instructions to users with a clickable info icon in the component headline using the rulesDisplay prop.
import { RulesDisplay } from "fansunited-frontend-core";
// Display rules in a modal dialog (default)
const rulesDisplay: RulesDisplay = {
type: "modal",
};
// Display rules as a clickable link
const rulesDisplay: RulesDisplay = {
type: "link",
url: "https://your-website.com/quiz-rules",
target: "_blank", // or "_self"
};
// Custom rules content component
const rulesDisplay: RulesDisplay = {
type: "modal",
component: <CustomRulesContent />,
};
<ClassicQuizPlay
{...otherProps}
rulesDisplay={rulesDisplay}
/>;Display Types:
Modal - Opens rules in a modal dialog overlay (default behavior)
- Uses the quiz's
rulesfield from the backend - Displays in a centered modal with close button
- Supports HTML content rendering
- Uses the quiz's
Link - Opens rules URL in a new tab/window
- Requires
urlproperty - Optional
targetproperty (_blankor_self) - Useful for external documentation or detailed rule pages
- Requires
Features:
- Info Icon: Displays a small info icon (ⓘ) next to the component headline
- Responsive: Adapts to all three templates (Standard, Split, Overlay)
- Theme-Aware: Automatically adjusts colors based on theme mode and variant
- Accessible: Keyboard navigable and screen reader friendly
- Non-Intrusive: Icon only appears when rules are configured
Behavior:
- The rules icon appears in the headline section across all component states (main view, sign-in, error, score state, lead collection)
- Modal dialogs can be closed by clicking the close button, clicking outside, or pressing Escape
- Link type opens in a new tab by default for better user experience
TypeScript Support
This package is built with TypeScript and provides full type definitions. Import types from fansunited-frontend-core:
import {
ClassicQuizPlayProps,
WidgetTemplate,
MainProps,
CustomThemeOptions,
LeadsOptions,
RulesDisplay,
SignInCTADetails,
AdditionalCTADetails,
AnalyticsEvent,
ChanceGameProps,
ChanceGameTemplate,
ChanceGameVariant,
} from "fansunited-frontend-core";Peer Dependencies
{
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}Bundle
The component uses shadow DOM and emotion for isolated styling, ensuring no CSS conflicts with your application.
Examples
Basic Quiz
import { ClassicQuizPlay } from "fansunited-frontend-components";
import { WidgetTemplate } from "fansunited-frontend-core";
<ClassicQuizPlay
entityId="quiz-123"
sdk={sdkInstance}
template={WidgetTemplate.STANDARD}
language="en"
/>;Customized Quiz
<ClassicQuizPlay
entityId="quiz-123"
sdk={sdkInstance}
template={WidgetTemplate.STANDARD}
imagePosition="right"
language="en"
showAnswerExplanations={true}
themeOptions={{
mode: "dark",
}}
leads={{
phoneCountryCode: "44",
syncWithProfile: true,
}}
/>PollVote
Interactive poll voting component with real-time results, multiple choice support, and customizable templates. Perfect for engaging audiences with opinion polls, surveys, and voting campaigns.
Key Features:
- Single and multiple choice voting
- Real-time vote results and percentages
- Three responsive templates (Standard, Split, Overlay)
- Lead collection integration
- Authentication support
- Vote attempt limits
- Custom theming and branding
Required Props
| Prop | Type | Description |
| ---------- | -------------------- | ----------------------- |
| entityId | string | Classic Quiz identifier |
| sdk | FansUnitedSDKModel | SDK instance |
| template | WidgetTemplate | Layout template |
| language | LanguageType | Display language |
Optional Props
| Prop | Type | Description |
| ---------------------------- | ----------------------- | ------------------------------------------- |
| themeOptions | CustomThemeOptions | Theme configuration |
| leads | LeadsOptions | Lead collection settings |
| imagePosition | "left" \| "right" | Image position (STANDARD template only) |
| defaultImagePlaceholderUrl | string | URL for default image placeholder |
| userIsLoggedIn | boolean | Determine if the user is logged in |
| signInCTA | SignInCTADetails | Sign in call to action button configuration |
| additionalCTA | AdditionalCTADetails | Additional call to action button configuration |
| rulesDisplay | RulesDisplay | Poll rules display configuration |
Templates
import { WidgetTemplate, PollVoteProps } from "fansunited-frontend-core";
// Standard template with optional image positioning
const standardProps: PollVoteProps = {
template: WidgetTemplate.STANDARD,
imagePosition: "left", // or 'right'
// ... other props
};
// Split template - side-by-side layout
const splitProps: PollVoteProps = {
template: WidgetTemplate.SPLIT,
// imagePosition not available for non-standard templates
// ... other props
};
// Overlay template - full-screen immersive experience
const overlayProps: PollVoteProps = {
template: WidgetTemplate.OVERLAY,
// ... other props
};Sign in Configuration
Control user authentication and voting permissions using the userIsLoggedIn and signInCTA props.
import { SignInCTADetails } from "fansunited-frontend-core";
// Custom sign-in component
const signInCTA: SignInCTADetails = {
component: <CustomSignInButton />,
};
// Basic sign-in with onClick handler
const signInCTA: SignInCTADetails = {
defaultLabel: "Sign in to vote",
onClick: () => {
// Handle sign-in logic
console.log("Sign in clicked");
},
};
// Sign-in with URL navigation
const signInCTA: SignInCTADetails = {
defaultLabel: "Login to participate",
url: "https://your-auth-provider.com/login",
target: "_blank",
};
<PollVote {...otherProps} userIsLoggedIn={false} signInCTA={signInCTA} />;Sign-in Priority Order:
- Custom Component - If
signInCTA.componentis provided, it will be rendered - Click Handler - If
signInCTA.onClickis provided, a button with the handler will be rendered - URL Navigation - If
signInCTA.urlis provided, a button will be rendered and clicking will navigate to the URL - Disabled - If no
signInCTAis provided, a disabled button will be shown
Behavior:
- When
userIsLoggedInisfalseand the poll requires authentication (authRequirement: "REGISTERED"), the sign-in screen will be displayed instead of the poll
Additional CTA Configuration
Add an extra call-to-action button to the poll results screen using the additionalCTA prop.
import { AdditionalCTADetails } from "fansunited-frontend-core";
// Custom component
const additionalCTA: AdditionalCTADetails = {
component: <CustomCTAButton />,
};
// Basic CTA with onClick handler
const additionalCTA: AdditionalCTADetails = {
defaultLabel: "Learn More",
onClick: () => {
// Handle click logic
console.log("Additional CTA clicked");
},
};
// CTA with URL navigation
const additionalCTA: AdditionalCTADetails = {
defaultLabel: "View Details",
url: "https://your-website.com/poll-details",
target: "_blank", // or "_self"
};
<PollVote
{...otherProps}
additionalCTA={additionalCTA}
/>;Priority Order:
- Custom Component - If
additionalCTA.componentis provided, it will be rendered - Click Handler - If
additionalCTA.onClickis provided, a button with the handler will be rendered - URL Navigation - If
additionalCTA.urlis provided, a button will be rendered and clicking will navigate to the URL
Placement:
- Standard variant: Displayed before "Vote Again" button
- Split variant: Displayed in the same container as "Vote Again" button
- Overlay variant: Displayed after "Vote Again" button
Lead Collection
Capture user information before or after voting:
import { LeadsOptions } from "fansunited-frontend-core";
const leads: LeadsOptions = {
position: "before", // "before" | "after"
fields: ["fullName", "email"], // Available: "fullName" | "firstName" | "lastName" | "email" | "gender" | "country" | "phoneCountryCode" | "phoneNumber"
campaignId: "poll-campaign-2024",
campaignName: "User Opinion Poll",
phoneCountryCode: "44", // Default country code for phone fields
syncWithProfile: true, // Optional: sync form data to user profile after successful submission
};
<PollVote {...otherProps} leads={leads} />;Profile Sync
When syncWithProfile is enabled in the leads configuration, form data will be automatically synced to the user's profile after successful submission:
import { LeadsOptions } from "fansunited-frontend-core";
const leads: LeadsOptions = {
position: "after",
fields: ["firstName", "lastName", "email", "phoneNumber", "country"],
campaignId: "user-profile-sync",
campaignName: "Profile Sync Campaign",
syncWithProfile: true, // Enable profile synchronization
};
<PollVote {...otherProps} leads={leads} />How it works:
- Only fields that are both included in the form configuration AND have non-empty values will be synced
- Supported fields:
fullName,firstName,lastName,email,phoneNumber,phoneCountryCode,country,gender - Uses the SDK profile namespace:
sdk.profile.getOwn().setName().setEmail()...update() - Profile sync failures are logged but don't break the lead collection flow
- Sync happens automatically after successful lead form submission
Name Field Priority:
- If
fullNameis configured and has a value, it takes priority for the profile name - If both
firstNameandlastNameare configured and have values, they are combined:"firstName lastName" - If only
firstNameis configured and has a value, it becomes the profile name - If only
lastNameis configured and has a value, it becomes the profile name
Examples
Basic Poll
import { PollVote } from "fansunited-frontend-components";
import { WidgetTemplate } from "fansunited-frontend-core";
<PollVote
entityId="poll-123"
sdk={sdkInstance}
template={WidgetTemplate.STANDARD}
language="en"
/>;Customized Poll
<PollVote
entityId="poll-123"
sdk={sdkInstance}
template={WidgetTemplate.OVERLAY}
language="en"
userIsLoggedIn={false}
signInCTA={{
defaultLabel: "Sign in to vote",
onClick: () => handleSignIn(),
}}
leads={{
position: "after",
fields: ["fullName", "email"],
campaignId: "poll-campaign",
campaignName: "User Survey 2024",
phoneCountryCode: "44",
syncWithProfile: true,
}}
themeOptions={{
mode: "dark",
}}
/>CollectLead
Lead collection component for capturing user information with customizable forms, branding, and success actions. Perfect for newsletter signups, contact forms, and user registration flows.
Key Features:
- Customizable form fields (name, email, phone, country, gender, custom fields)
- Consent management and privacy policy integration
- Custom branding and theming support
- Success page with custom CTAs
- Three responsive templates (Standard, Split, Overlay)
- Phone number validation with country codes
- Multi-language support
Required Props
| Prop | Type | Description |
| ---------- | -------------------- | ------------------------------- |
| entityId | string | Lead collection form identifier |
| sdk | FansUnitedSDKModel | SDK instance |
| template | WidgetTemplate | Layout template |
| language | LanguageType | Display language |
Optional Props
| Prop | Type | Description |
| ---------------------------- | --------------------- | ----------------------------------------- |
| themeOptions | CustomThemeOptions | Theme configuration |
| fields | LeadField[] | Form fields to display |
| labels | LeadLabels | Custom labels for form elements |
| imagePosition | "left" \| "right" | Image position (STANDARD template only) |
| defaultImagePlaceholderUrl | string | URL for default image placeholder |
| phoneCountryCode | string | Default country code for phone fields |
| syncWithProfile | boolean | Sync form data to user profile after successful submission |
| onSuccessCTA | OnSuccessCTADetails | Success page call to action configuration |
| customFields | LeadCustomField[] | Additional custom form fields |
| consents | LeadConsent[] | Consent checkboxes for privacy compliance |
| content | ContentInfo | Content metadata |
| campaign | CampaignInfo | Campaign information |
| branding | BrandingInfo | Branding configuration |
| images | ImagesModel | Image assets |
Templates
import { WidgetTemplate, CollectLeadProps } from "fansunited-frontend-core";
// Standard template with optional image positioning
const standardProps: CollectLeadProps = {
template: WidgetTemplate.STANDARD,
imagePosition: "left", // or 'right'
// ... other props
};
// Split template - side-by-side layout
const splitProps: CollectLeadProps = {
template: WidgetTemplate.SPLIT,
// imagePosition not available for non-standard templates
// ... other props
};
// Overlay template - full-screen immersive experience
const overlayProps: CollectLeadProps = {
template: WidgetTemplate.OVERLAY,
// ... other props
};Form Configuration
Configure which fields to display and their behavior:
import {
LeadField,
LeadCustomField,
LeadConsent,
} from "fansunited-frontend-core";
// Standard form fields
const fields: LeadField[] = [
"fullName",
"email",
"phoneNumber",
"country",
"gender",
];
// Custom fields for additional data collection
const customFields: LeadCustomField[] = [
{
key: "company",
label: "Company Name",
type: "input",
required: true,
placeholder: "Enter your company name",
},
{
key: "message",
label: "Message",
type: "textarea",
required: false,
placeholder: "Tell us about your needs...",
},
];
// Consent checkboxes for privacy compliance
const consents: LeadConsent[] = [
{
id: "marketing",
label: "I agree to receive marketing communications",
},
{
id: "newsletter",
label: "Subscribe to our newsletter",
},
];
<CollectLead
{...otherProps}
fields={fields}
customFields={customFields}
consents={consents}
/>;Custom Labels
Customize all text displayed in the form:
import { LeadLabels } from "fansunited-frontend-core";
const labels: LeadLabels = {
title: "Join Our Community",
description: "Get exclusive updates and early access to new features",
formTitle: "Sign Up Today",
formDescription: "Fill out the form below to get started",
formFullNameLabel: "Full Name",
formFullNamePlaceholder: "Enter your full name",
formEmailLabel: "Email Address",
formGenderLabel: "Gender",
formGenderPlaceholder: "Select your gender",
formCountryLabel: "Country",
formCountryPlaceholder: "Select your country",
formPhoneNumberLabel: "Phone Number",
formPhoneNumberPlaceholder: "Enter your phone number",
submitButtonLabel: "Subscribe Now",
successTitle: "Welcome Aboard!",
successDescription:
"Thank you for joining our community. Check your email for next steps.",
privacyPolicyUrlLabel: "Privacy Policy",
termsAndConditionsUrlLabel: "Terms & Conditions",
presentedByLabel: "Powered by",
};
<CollectLead {...otherProps} labels={labels} />;Success Actions
Configure what happens after successful form submission:
import { OnSuccessCTADetails } from "fansunited-frontend-core";
// Custom success action with onClick handler
const onSuccessCTA: OnSuccessCTADetails = {
defaultLabel: "Continue to Dashboard",
onClick: () => {
// Handle post-submission logic
window.location.href = "/dashboard";
},
};
// Success action with URL navigation
const onSuccessCTA: OnSuccessCTADetails = {
defaultLabel: "Visit Our Website",
url: "https://your-website.com",
target: "_blank",
};
// Custom success component
const onSuccessCTA: OnSuccessCTADetails = {
component: <CustomSuccessButton />,
};
<CollectLead {...otherProps} onSuccessCTA={onSuccessCTA} />;Profile Sync
Enable automatic profile synchronization to update user profiles with form data:
<CollectLead
entityId="lead-form-123"
sdk={sdkInstance}
template={WidgetTemplate.STANDARD}
language="en"
fields={["firstName", "lastName", "email", "phoneNumber", "country", "gender"]}
syncWithProfile={true} // Enable profile synchronization
labels={{
title: "Update Your Profile",
submitButtonLabel: "Save & Update Profile",
}}
/>Profile Sync Features:
- Automatic Sync: Form data is automatically synced to the user's profile after successful submission
- Field Mapping: Only configured fields with non-empty values are synced to the profile
- Supported Fields:
fullName,firstName,lastName,email,phoneNumber,phoneCountryCode,country,gender - SDK Integration: Uses the profile builder pattern:
sdk.profile.getOwn().setName().setEmail()...update() - Error Handling: Profile sync failures are logged but don't prevent lead collection
- Optional: Defaults to
false, completely opt-in behavior
Name Field Handling:
- Priority 1:
fullName(if configured and has value) → sets profile name directly - Priority 2:
firstName+lastName(if both configured and have values) → combined as"firstName lastName" - Priority 3:
firstNameonly (if configured and has value) → sets profile name - Priority 4:
lastNameonly (if configured and has value) → sets profile name
Use Cases:
- User registration forms that also update profiles
- Newsletter signups that capture additional profile information
- Contact forms that enhance user profiles with new data
- Profile update forms with lead tracking
Examples
Basic Lead Form
import { CollectLead } from "fansunited-frontend-components";
import { WidgetTemplate } from "fansunited-frontend-core";
<CollectLead
entityId="lead-form-123"
sdk={sdkInstance}
template={WidgetTemplate.STANDARD}
language="en"
fields={["fullName", "email"]}
/>;Advanced Lead Form
<CollectLead
entityId="lead-form-123"
sdk={sdkInstance}
template={WidgetTemplate.OVERLAY}
language="en"
fields={["fullName", "email", "phoneNumber", "country"]}
phoneCountryCode="44"
syncWithProfile={true}
customFields={[
{
key: "company",
label: "Company",
type: "input",
required: true,
},
]}
consents={[
{
id: "marketing",
label: "I agree to receive marketing emails",
},
]}
labels={{
title: "Get Early Access",
submitButtonLabel: "Join Waitlist",
successTitle: "You're In!",
successDescription: "We'll notify you when we launch.",
}}
onSuccessCTA={{
defaultLabel: "Learn More",
url: "https://example.com/learn-more",
target: "_blank",
}}
themeOptions={{
mode: "dark",
}}
/>PersonalityQuizPlay
Interactive personality quiz component that matches users with personas based on their answers. Features comprehensive result displays with persona matching, detailed explanations, and customizable templates.
Key Features:
- Personality matching algorithm with percentage scores
- Multiple persona results with detailed descriptions
- Tabbed result interface with top match highlighting
- Answer explanations and persona insights
- Three responsive templates (Standard, Split, Overlay)
- Lead collection integration
- Authentication support
- Custom theming and branding
- Result sharing capabilities
Required Props
| Prop | Type | Description |
| ---------- | -------------------- | --------------------------- |
| entityId | string | Personality Quiz identifier |
| sdk | FansUnitedSDKModel | SDK instance |
| template | WidgetTemplate | Layout template |
| language | LanguageType | Display language |
Optional Props
| Prop | Type | Description |
| ---------------------------- | ----------------------- | ------------------------------------------- |
| themeOptions | CustomThemeOptions | Theme configuration |
| showAnswerExplanations | boolean | Show explanations after quiz completion |
| leads | LeadsOptions | Lead collection settings |
| imagePosition | "left" \| "right" | Image position (STANDARD template only) |
| defaultImagePlaceholderUrl | string | URL for default image placeholder |
| userIsLoggedIn | boolean | Determine if the user is logged in |
| signInCTA | SignInCTADetails | Sign in call to action button configuration |
| additionalCTA | AdditionalCTADetails | Additional call to action button configuration |
| optionsLayout | OptionsLayout | Layout for answer options |
| rulesDisplay | RulesDisplay | Quiz rules display configuration |
Templates
import {
WidgetTemplate,
PersonalityQuizPlayProps,
} from "fansunited-frontend-core";
// Standard template with optional image positioning
const standardProps: PersonalityQuizPlayProps = {
template: WidgetTemplate.STANDARD,
imagePosition: "left", // or 'right'
// ... other props
};
// Split template - side-by-side layout
const splitProps: PersonalityQuizPlayProps = {
template: WidgetTemplate.SPLIT,
// imagePosition not available for non-standard templates
// ... other props
};
// Overlay template - full-screen immersive experience
const overlayProps: PersonalityQuizPlayProps = {
template: WidgetTemplate.OVERLAY,
// ... other props
};Options Layout
Configure how answer options are displayed:
import { OptionsLayout } from "fansunited-frontend-core";
// Two-by-two grid layout
const twoByTwoLayout: PersonalityQuizPlayProps = {
optionsLayout: "twoByTwo",
// ... other props
};
// Horizontal row layout
const rowLayout: PersonalityQuizPlayProps = {
optionsLayout: "row",
// ... other props
};
// Vertical column layout
const columnLayout: PersonalityQuizPlayProps = {
optionsLayout: "column",
// ... other props
};Sign in Configuration
Control user authentication and quiz access using the userIsLoggedIn and signInCTA props.
import { SignInCTADetails } from "fansunited-frontend-core";
// Custom sign-in component
const signInCTA: SignInCTADetails = {
component: <CustomSignInButton />,
};
// Basic sign-in with onClick handler
const signInCTA: SignInCTADetails = {
defaultLabel: "Sign in to take quiz",
onClick: () => {
// Handle sign-in logic
console.log("Sign in clicked");
},
};
// Sign-in with URL navigation
const signInCTA: SignInCTADetails = {
defaultLabel: "Login to discover your personality",
url: "https://your-auth-provider.com/login",
target: "_blank",
};
<PersonalityQuizPlay
{...otherProps}
userIsLoggedIn={false}
signInCTA={signInCTA}
/>;Sign-in Priority Order:
- Custom Component - If
signInCTA.componentis provided, it will be rendered - Click Handler - If
signInCTA.onClickis provided, a button with the handler will be rendered - URL Navigation - If
signInCTA.urlis provided, a button will be rendered and clicking will navigate to the URL - Disabled - If no
signInCTAis provided, a disabled button will be shown
Behavior:
- When
userIsLoggedInisfalseand the quiz requires authentication (authRequirement: "REGISTERED"), the sign-in screen will be displayed instead of the quiz
Additional CTA Configuration
Add an extra call-to-action button to the quiz results screen using the additionalCTA prop.
import { AdditionalCTADetails } from "fansunited-frontend-core";
// Custom component
const additionalCTA: AdditionalCTADetails = {
component: <CustomCTAButton />,
};
// Basic CTA with onClick handler
const additionalCTA: AdditionalCTADetails = {
defaultLabel: "Explore More",
onClick: () => {
// Handle click logic
console.log("Additional CTA clicked");
},
};
// CTA with URL navigation
const additionalCTA: AdditionalCTADetails = {
defaultLabel: "Discover Your Type",
url: "https://your-website.com/personality-types",
target: "_blank", // or "_self"
};
<PersonalityQuizPlay
{...otherProps}
additionalCTA={additionalCTA}
/>;Priority Order:
- Custom Component - If
additionalCTA.componentis provided, it will be rendered - Click Handler - If
additionalCTA.onClickis provided, a button with the handler will be rendered - URL Navigation - If
additionalCTA.urlis provided, a button will be rendered and clicking will navigate to the URL
Placement:
- Standard variant: Displayed before "Play Again" button
- Split variant: Displayed in the thank you container after "Play Again" button
- Overlay variant: Displayed after "Play Again" button if available
Lead Collection
Capture user information before or after taking the personality quiz:
import { LeadsOptions } from "fansunited-frontend-core";
const leads: LeadsOptions = {
position: "before", // "before" | "after"
fields: ["fullName", "email"], // Available: "fullName" | "firstName" | "lastName" | "email" | "gender" | "country" | "phoneCountryCode" | "phoneNumber"
campaignId: "personality-quiz-2024",
campaignName: "Personality Assessment Campaign",
phoneCountryCode: "1", // Default country code for phone fields
syncWithProfile: true, // Optional: sync form data to user profile after successful submission
};
<PersonalityQuizPlay {...otherProps} leads={leads} />;Answer Explanations
Enable detailed explanations for quiz answers and persona matching:
<PersonalityQuizPlay {...otherProps} showAnswerExplanations={true} />When enabled, users will see:
- Explanations for each answer choice
- Detailed persona descriptions
- Matching algorithm insights
- Percentage breakdowns for each persona
Examples
Basic Personality Quiz
import { PersonalityQuizPlay } from "fansunited-frontend-components";
import { WidgetTemplate } from "fansunited-frontend-core";
<PersonalityQuizPlay
entityId="personality-quiz-123"
sdk={sdkInstance}
template={WidgetTemplate.STANDARD}
language="en"
/>;Advanced Personality Quiz
<PersonalityQuizPlay
entityId="personality-quiz-123"
sdk={sdkInstance}
template={WidgetTemplate.OVERLAY}
language="en"
showAnswerExplanations={true}
optionsLayout="twoByTwo"
userIsLoggedIn={false}
signInCTA={{
defaultLabel: "Sign in to save results",
onClick: () => handleSignIn(),
}}
leads={{
position: "after",
fields: ["fullName", "email"],
campaignId: "personality-campaign",
campaignName: "Personality Assessment 2024",
phoneCountryCode: "44",
syncWithProfile: true,
}}
themeOptions={{
mode: "dark",
colorSchemes: {
dark: {
textPrimary: "#ffffff",
surface: "#1a1a1a",
},
},
}}
/>Customized Layout
<PersonalityQuizPlay
entityId="personality-quiz-123"
sdk={sdkInstance}
template={WidgetTemplate.STANDARD}
imagePosition="right"
language="en"
optionsLayout="column"
showAnswerExplanations={true}
themeOptions={{
mode: "light",
customFontFamily: {
light: {
primary: "Inter, sans-serif",
secondary: "Roboto, sans-serif",
},
},
}}
/>PickThePair
Interactive pair matching game component that challenges users to match related items from two columns. Features two game modes (casual and challenge), optional countdown timer, real-time accuracy tracking, and customizable templates. Perfect for educational quizzes, trivia games, and engaging brand experiences.
Key Features:
- Two game modes: Casual (relaxed matching) and Challenge (accuracy-based with success threshold)
- Optional countdown timer with configurable time limits
- Real-time accuracy tracking and statistics
- Visual feedback for correct/incorrect matches
- Dynamic image reveal on selection
- Three responsive templates (Standard, Landing Page, Overlay)
- Lead collection integration
- Custom theming and branding
- Mobile-optimized interface
Required Props
| Prop | Type | Description |
| ---------- | ----------------------- | -------------------------- |
| entityId | string | Pick The Pair identifier |
| sdk | FansUnitedSDKModel | SDK instance |
| template | PickThePairTemplate | Layout template |
| language | LanguageType | Display language |
Optional Props
| Prop | Type | Description |
| ---------------------------- | ---------------------- | ----------------------------------------- |
| themeOptions | CustomThemeOptions | Theme configuration |
| leads | LeadsOptions | Lead collection settings |
| imagePosition | "left" \| "right" | Image position (STANDARD template only) |
| defaultImagePlaceholderUrl | string | URL for default image placeholder |
Templates
import { PickThePairTemplate, PickThePairProps } from "fansunited-frontend-core";
// Standard template - traditional card-based layout with optional image positioning
const standardProps: PickThePairProps = {
template: PickThePairTemplate.STANDARD,
imagePosition: "left", // or 'right'
// ... other props
};
// Landing Page template - full-width immersive experience
const landingPageProps: PickThePairProps = {
template: PickThePairTemplate.LANDING_PAGE,
// imagePosition not available for non-standard templates
// ... other props
};
// Overlay template - full-screen overlay experience
const overlayProps: PickThePairProps = {
template: PickThePairTemplate.OVERLAY,
// imagePosition not available for non-standard templates
// ... other props
};Template Differences:
- Standard: Traditional card-based layout with clear separation between game area and branding. Supports
imagePositionprop to control image placement. - Landing Page: Full-width design optimized for standalone pages with prominent branding
- Overlay: Full-screen immersive experience with background image and overlay effects
Game Modes
PickThePair supports two distinct game modes:
Casual Mode:
- Relaxed matching experience without scoring pressure
- No accuracy requirements or success thresholds
- Players can take their time to match all pairs
- Perfect for educational content and brand awareness
Challenge Mode:
- Competitive experience with accuracy tracking
- Success threshold requirement (configurable percentage)
- Real-time statistics display showing:
- Total attempts made
- Current accuracy percentage
- Success threshold indicator
- Matched pairs count
- Players must meet the accuracy threshold to proceed
- Ideal for competitive campaigns and skill-based challenges
Countdown Timer
Enable time-limited challenges with the countdown timer feature:
How it works:
- Timer is configured in Info Pages Management in Pick The Pair configuration time limit (in seconds)
- Set to
0for no time limit - When
> 0, a countdown timer is displayed - Timer starts automatically when the game loads
- Visual countdown shows remaining time
- When time expires:
- All selections are disabled
- "Time's Up" (label timeUp) overlay is displayed
- Players cannot continue matching
- Submit button becomes disabled
Timer Display:
- Shows minutes and seconds in MM:SS format
- Updates in real-time
- Styled with branding colors
- Responsive design for mobile and desktop
Accuracy Tracking
In Challenge Mode, the component tracks and displays detailed statistics:
Tracked Metrics:
- Total Attempts: Number of match attempts made
- Correct Matches: Successfully matched pairs
- Incorrect Attempts: Failed match attempts
- Accuracy Percentage: (Correct Matches / Total Attempts) × 100
- Success Threshold: Required accuracy to proceed
Visual Indicators:
- Real-time accuracy display
- Color-coded threshold indicator (green when met, red when not met)
- Progress bar showing matched pairs vs total pairs
- Success/failure state based on threshold
Behavior:
- Players must achieve the required accuracy percentage to submit
- Submit button is disabled until threshold is met (in Challenge Mode)
- Statistics update in real-time after each match attempt
Matching Mechanics
How Matching Works:
- Selection: Click an item from the left column and an item from the right column or vice-versa
- Validation: The component checks if both items have the same pair ID
- Feedback:
- Correct Match: Items remain selected, images are revealed (if available), pair is marked as matched
- Incorrect Match: Red error animation plays for 800ms, both selections are cleared
- Completion: All pairs must be matched to enable the submit/continue button
Visual States:
- Unselected: Default state with option text visible
- Selected: Highlighted with primary color, image revealed (if available)
- Matched: Success color (green), image remains visible, item disabled
- Error: Danger color (red) animation on incorrect match
- Disabled: Grayed out when time is up or during error animation
Image Behavior:
- Images are hidden by default
- Revealed when an item is selected or matched
- Left column: Image appears on the right side of the text
- Right column: Image appears on the left side of the text
- Supports both desktop (
main) and mobile (mobile) image variants - Gracefully handles pairs without images
Lead Collection
Capture user information before or after the matching game:
import { LeadsOptions } from "fansunited-frontend-core";
const leads: LeadsOptions = {
position: "after", // only after is supported
fields: ["fullName", "email"], // Available: "fullName" | "firstName" | "lastName" | "email" | "gender" | "country" | "phoneCountryCode" | "phoneNumber"
campaignId: "pick-the-pair-campaign",
campaignName: "Brand Matching Challenge",
phoneCountryCode: "1", // Default country code for phone fields
};
<PickThePair {...otherProps} leads={leads} />;Lead Collection Features:
- Flexible Fields: Choose which user information to collect
- Profile Sync: Optionally sync collected data to user profiles
- Custom Branding: Lead forms inherit game branding and theme
- Success State: Confirmation message after successful submission
Examples
Basic Pair Matching Game
import { PickThePair } from "fansunited-frontend-components";
import { PickThePairTemplate } from "fansunited-frontend-core";
<PickThePair
entityId="pair-matching-123"
sdk={sdkInstance}
template={PickThePairTemplate.STANDARD}
language="en"
/>;Challenge Mode with Timer
// Backend configuration:
// {
// "mode": "challenge",
// "timeLimit": 120,
// "successThresholdPercent": 75
// }
<PickThePair
entityId="timed-challenge-123"
sdk={sdkInstance}
template={PickThePairTemplate.LANDING_PAGE}
language="en"
themeOptions={{
mode: "dark",
}}
/>Complete Setup with Lead Collection
<PickThePair
entityId="brand-quiz-123"
sdk={sdkInstance}
template={PickThePairTemplate.OVERLAY}
language="en"
leads={{
position: "after",
fields: ["fullName", "email", "phoneNumber"],
campaignId: "brand-awareness-2024",
campaignName: "Product Knowledge Challenge",
phoneCountryCode: "44",
syncWithProfile: true,
}}
themeOptions={{
mode: "light",
colorSchemes: {
light: {
palette: {
primary: {
plainColor: "#FF5722",
primaryContainer: "#FF7043",
},
success: {
plainColor: "#4CAF50",
softBg: "#E8F5E9",
},
danger: {
plainColor: "#F44336",
softBg: "#FFEBEE",
},
},
},
},
}}
defaultImagePlaceholderUrl="https://example.com/placeholder.png"
/>Casual Mode for Education
// Backend configuration:
// {
// "mode": "casual",
// "timeLimit": 0,
// "successThresholdPercent": 0
// }
<PickThePair
entityId="educational-pairs-123"
sdk={sdkInstance}
template={PickThePairTemplate.STANDARD}
imagePosition="right"
language="en"
themeOptions={{
mode: "light",
customFontFamily: {
light: {
primary: "Poppins, sans-serif",
secondary: "Open Sans, sans-serif",
},
},
}}
/>MatchQuizPlay
Interactive match prediction quiz component that allows users to make predictions on various football match markets. Features multiple fixture types, real-time countdown timers, points system, and comprehensive result tracking with leaderboards.
Key Features:
- Multiple prediction markets (1X2, Correct Score, Player Markets, Over/Under Goals, Corners, etc.)
- Real-time countdown timer for prediction cutoff
- Points system with loyalty integration
- Leaderboard and ranking system
- Prediction summary and editing capabilities
- Three responsive templates (Standard, Split, Overlay)
- Lead collection integration
- Authentication support
- Custom theming and branding
- Detailed prediction results and explanations
Required Props
| Prop | Type | Description |
| ---------- | -------------------- | --------------------- |
| entityId | string | Match Quiz identifier |
| sdk | FansUnitedSDKModel | SDK instance |
| template | WidgetTemplate | Layout template |
| language | LanguageType | Display language |
Optional Props
| Prop | Type | Description |
| ---------------------------- | ----------------------- | ------------------------------------------------- |
| themeOptions | CustomThemeOptions | Theme configuration |
| leads | LeadsOptions | Lead collection settings |
| imagePosition | "left" \| "right" | Image position (STANDARD template only) |
| defaultImagePlaceholderUrl | string | URL for default image placeholder |
| userIsLoggedIn | boolean | Determine if the user is logged in |
| signInCTA | SignInCTADetails | Sign in call to action button configuration |
| additionalCTA | AdditionalCTADetails | Additional call to action button configuration |
| showCountdown | boolean | Show countdown timer when Match Quiz is open |
| showTeamLabels | boolean | Show team name labels in fixture components |
| showPoints | boolean | Show points display for each fixture |
| showPredictionDetails | boolean | Show detailed prediction results after completion |
| rulesDisplay | RulesDisplay | Match quiz rules display configuration |
Templates
import { WidgetTemplate, MatchQuizPlayProps } from "fansunited-frontend-core";
// Standard template with optional image positioning
const standardProps: MatchQuizPlayProps = {
template: WidgetTemplate.STANDARD,
imagePosition: "left", // or 'right'
// ... other props
};
// Split template - side-by-side layout
const splitProps: MatchQuizPlayProps = {
template: WidgetTemplate.SPLIT,
// imagePosition not available for non-standard templates
// ... other props
};
// Overlay template - full-screen immersive experience
const overlayProps: MatchQuizPlayProps = {
template: WidgetTemplate.OVERLAY,
// ... other props
};Supported Markets
MatchQuizPlay supports a wide variety of football prediction markets:
Match Result Markets:
FT_1X2- Full Time 1X2 (Home Win, Draw, Away Win)HT_1X2- Half Time 1X2
Score Markets:
CORRECT_SCORE- Exact final score predictionCORRECT_SCORE_HT- Exact half-time score predictionCORRECT_SCORE_ADVANCED- Advanced correct score with alternative points
Player Markets:
PLAYER_SCORE_FIRST_GOAL- First goalscorer predictionPLAYER_SCORE- Anytime goalscorerPLAYER_YELLOW_CARD- Player to receive yellow cardPLAYER_RED_CARD- Player to receive red cardPLAYER_SCORE_HATTRICK- Player to score hat-trickPLAYER_SCORE_TWICE- Player to score twice
Over/Under Markets:
OVER_GOALS_0_5toOVER_GOALS_6_5- Total goals over/underOVER_CORNERS_6_5toOVER_CORNERS_13_5- Total corners over/under
Special Markets:
CORNERS_MATCH- Total corners in the matchPENALTY_MATCH- Penalty awarded in the matchRED_CARD_MATCH- Red card shown in the match
Game Status States
Match quizzes have 5 distinct status states:
PENDING- Not yet open for predictionsOPEN- Ready for predictions (default state)LIVE- Match has started, no new predictions acceptedCLOSED- Match finished, backend resolving predictionsSETTLED- Predictions resolved, leaderboard available
Countdown Timer
Enable countdown timer to show time remaining for predictions:
<MatchQuizPlay {...otherProps} showCountdown={true} />The countdown timer:
- Displays when Match Quiz status is
OPEN - Shows days, hours, minutes, and seconds remaining
- Uses
predictionsCutoffTimefrom the Match Quiz data - Automatically hides when cutoff time is reached
Points System
Enable points display to show potential rewards:
<MatchQuizPlay {...otherProps} showPoints={true} />Points system features:
- Shows potential points for each fixture
- Displays earned vs possible points
- Integrates with loyalty system configuration
- Supports alternative point structures for advanced markets
- Mobile-friendly tooltip display
Prediction Details
Show detailed prediction results and explanations:
<MatchQuizPlay {...otherProps} showPredictionDetails={true} />When enabled, users see:
- Tabulated interface
- Correct vs incorrect prediction highlighting
- Detailed market results
- Points breakdown per fixture
Sign in Configuration
Control user authentication and quiz access using the userIsLoggedIn and signInCTA props.
import { SignInCTADetails } from "fansunited-frontend-core";
// Custom sign-in component
const signInCTA: SignInCTADetails = {
component: <CustomSignInButton />,
};
// Basic sign-in with onClick handler
const signInCTA: SignInCTADetails = {
defaultLabel: "Sign in to predict",
onClick: () => {
// Handle sign-in logic
console.log("Sign in clicked");
},
};
// Sign-in with URL navigation
const signInCTA: SignInCTADetails = {
defaultLabel: "Login to join the competition",
url: "https://your-auth-provider.com/login",
target: "_blank",
};
<MatchQuizPlay {...otherProps} userIsLoggedIn={false} signInCTA={signInCTA} />;Sign-in Priority Order:
- Custom Component - If
signInCTA.componentis provided, it will be rendered - Click Handler - If
signInCTA.onClickis provided, a button with the handler will be rendered - URL Navigation - If
signInCTA.urlis provided, a button will be rendered and clicking will navigate to the URL - Disabled - If no
signInCTAis provided, a disabled button will be shown
Behavior:
- When
userIsLoggedInisfalseand the quiz requires authentication (authRequirement: "REGISTERED"), the sign-in screen will be displayed instead of the quiz
Additional CTA Configuration
Add an extra call-to-action button to the match quiz results screen using the additionalCTA prop.
import { AdditionalCTADetails } from "fansunited-frontend-core";
// Custom component
const additionalCTA: AdditionalCTADetails = {
component: <CustomCTAButton />,
};
// Basic CTA with onClick handler
const additionalCTA: AdditionalCTADetails = {
defaultLabel: "View Leaderboard",
onClick: () => {
// Handle click logic
console.log("Additional CTA clicked");
},
};
// CTA with URL navigation
const additionalCTA: AdditionalCTADetails = {
defaultLabel: "Match Details",
url: "https://your-website.com/match-details",
target: "_blank", // or "_self"
};
<MatchQuizPlay
{...otherProps}
additionalCTA={additionalCTA}
/>;Priority Order:
- Custom Component - If
additionalCTA.componentis provided, it will be rendered - Click Handler - If
additionalCTA.onClickis provided, a button with the handler will be rendered - URL Navigation - If
additionalCTA.urlis provided, a button will be rendered and clicking will navigate to the URL
Placement:
- Standard variant: Displayed on the same line as the branding logo
- Split variant: Displayed centered after main content
- Overlay variant: Displayed on the same line as the branding logo
Lead Collection
Capture user information before or after making predictions:
import { LeadsOptions } from "fansunited-frontend-core";
const leads: LeadsOptions = {
position: "before", // "before" | "after"
fields: ["fullName", "email"], // Available: "fullName" | "firstName" | "lastName" | "email" | "gender" | "country" | "phoneCountryCode" | "phoneNumber"
campaignId: "match-quiz-2024",
campaignName: "Football Prediction Campaign",
phoneCountryCode: "44", // Default country code for phone fields
syncWithProfile: true, // Optional: sync form data to user profile after successful submission
};
<MatchQuizPlay {...otherProps} leads={leads} />;Examples
Basic Match Quiz
import { MatchQuizPlay } from "fansunited-frontend-components";
import { WidgetTemplate } from "fansunited-frontend-core";
<MatchQuizPlay
entityId="match-quiz-123"
sdk={sdkInstance}
template={WidgetTemplate.STANDARD}
language="en"
/>;Advanced Match Quiz
<MatchQuizPlay
entityId="match-quiz-123"
sdk={sdkInstance}
template={WidgetTemplate.OVERLAY}
language="en"
showCountdown={true}
showTeamLabels={true}
showPoints={true}
showPredictionDetails={true}
userIsLoggedIn={false}
signInCTA={{
defaultLabel: "Sign in to compete",
onClick: () => handleSignIn(),
}}
leads={{
position: "after",
fields: ["fullName", "email"],
campaignId: "match-prediction-campaign",
campaignName: "Football Predictions 2024",
phoneCountryCode: "44",
syncWithProfile: true,
}}
themeOptions={{
mode: "dark",
colorSchemes: {
dark: {
textPrimary: "#ffffff",
surface: "#1a1a1a",
},
},
}}
/>Customized Layout
<MatchQuizPlay
entityId="match-quiz-123"
sdk={sdkInstance}
template={WidgetTemplate.STANDARD}
imagePosition="right"
language="en"
showCountdown={true}
showTeamLabels={false}
showPoints={true}
themeOptions={{
mode: "light",
customFontFamily: {
light: {
primary: "Inter, sans-serif",
secondary: "Roboto, sans-serif",
},
},
}}
/>EventGamePlay
Interactive event prediction component for sports and entertainment events. Features flexible fixture types, real-time countdown timers, points system, and comprehensive result tracking with leaderboards.
Key Features:
- Multiple outcome types (Boolean, Number, Enum, Free Input)
- Real-time countdown timer for prediction cutoff
- Points system with loyalty integration
- Leaderboard and ranking system
- Prediction summary and editing capabilities
- Three responsive templates (Standard, Split, Overlay)
- Custom theming
Required Props
| Prop | Type | Description |
| ---------- | -------------------- | --------------------- |
| entityId | string | Event Game identifier |
| sdk | FansUnitedSDKModel | SDK instance |
| template | WidgetTemplate | Layout template |
| language | LanguageType | Display language |
Optional Props
| Prop | Type | Description |
| ---------------------------- | ----------------------- | ------------------------------------------------- |
| themeOptions | CustomThemeOptions | Theme configuration |
| leads | LeadsOptions | Lead collection settings |
| imagePosition | "left" \| "right" | Image position (STANDARD template only) |
| defaultImagePlaceholderUrl | string | URL for default image placeholder |
| userIsLoggedIn | boolean | Determine if the user is logged in |
| signInCTA | SignInCTADetails | Sign in call to action button configuration |
| additionalCTA | AdditionalCTADetails | Additional call to action button configuration |
| showCountdown | boolean | Show countdown timer when Event Game is open |
| showPoints | boolean | Show points display for each fixture |
| showPredictionDetails | boolean | Show detailed prediction results after completion |
| rulesDisplay | RulesDisplay | Event game rules display configuration |
Templates
import { WidgetTemplate, EventGamePlayProps } from "fansunited-frontend-core";
// Standard template with optional image positioning
const standardProps: EventGamePlayProps = {
template: WidgetTemplate.STANDARD,
imagePosition: "left", // or 'right'
// ... other props
};
// Split template - side-by-side layout
const splitProps: EventGamePlayProps = {
template: WidgetTemplate.SPLIT,
// imagePosition not available for non-standard templates
// ... other props
};
// Overlay template - full-screen immersive experience
const overlayProps: EventGamePlayProps = {
template: WidgetTemplate.OVERLAY,
// ... other props
};Supported Outcome Types
EventGamePlay supports flexible prediction types for various event scenarios:
Boolean Outcomes:
BOOLEAN- Yes/No predictions (e.g., "Will the total points exceed 225?")
Number Outcomes:
NUMBER- Numeric predictions with optional min/max validation (e.g., "How many total points will be scored?")
Enum Outcomes:
ENUM- Multiple choice selection from predefined options (e.g., "Who will be the game's leading scorer?")
Free Input Outcomes:
FREE_INPUT- Open text input for custom predictions (e.g., "What will be the exact final score?")
Game Status States
Event games have 5 distinct status states:
PENDING- Not yet open for predictionsOPEN- Ready for predictions (default state)LIVE- Event has started, no new predictions acceptedCLOSED- Event finished, backend resolving predictionsSETTLED- Predictions resolved, leaderboard available
Countdown Timer
Enable countdown timer to show time remaining for predictions:
<EventGamePlay {...otherProps} showCountdown={true} />The countdown timer:
- Displays when Event Game status is
OPEN - Shows days, hours, minutes, and seconds remaining
- Uses
predictionsCutofffrom the Event Game data - Automatically hides when cutoff time is reached
Points System
Enable points display to show potential rewards:
<EventGamePlay {...otherProps} showPoints={true} />Points system features:
- Shows potential points for each fixture
- Mobile-friendly tooltip display
Prediction Details
Show detailed prediction results and explanations:
<EventGamePlay {...otherProps} showPredictionDetails={true} />When enabled, users see:
- Tabulated interface showing all predictions
- Correct vs incorrect prediction highlighting
- Comparison with correct outcomes
Additional CTA Configuration
Add an extra call-to-action button to the event game results screen using the additionalCTA prop.
import { AdditionalCTADetails } from "fansunited-frontend-core";
// Custom component
const additionalCTA: AdditionalCTADetails = {
component: <CustomCTAButton />,
};
// Basic CTA with onClick handler
const additionalCTA: AdditionalCTADetails = {
defaultLabel: "View Leaderboard",
onClick: () => {
// Handle click logic
console.log("Additional CTA cl