Arc Subscriptions
This is an out of the box solution for Arc Subscriptions that offers three different levels of components to suit your needs plus convenience functions.
-
SPAs - these requires only minimal style customization and configuration with the option to pass in custom localization. It includes all of the workflows pre-built into two different components for you to get up and running on Arc Subscriptions as soon as possible with minimal effort. One is designed for logging in and user profile/account management and the other allows the user to purchase products and follow the checkout and payment workflow.
-
Identity - login, lost password, verify email, profile, manage subscriptions, order history
-
Retail - offers/products, cart, payment processing, order confirmation
-
Custom SPA - shows an example of how to create your own custom SPA
-
-
Forms - these are pre-built forms for the different areas of Arc Subscriptions that you can highly customize or use as they are to create your own workflows or to meet the specific needs of your project.
-
Identity Forms - forms related to account creation and management, email verification and password resets
-
Retail & Sales Forms - forms offers/products and shopping cart
-
Paywall - all variations of the paywall forms and an example component
-
Custom Form - an example of how to create your own custom form
-
-
Elements - these are all of the form sub-components that make up Arc Subscriptions so that you can create and build your highly customizable forms and workflows to meet the specific needs of your project
-
Functions & Analytics - these are functions and events you can use to help with your custom form creations or for customizing a specific form.
-
Analytics - call these or listen to these for your analytics reporting
-
Input Validation - validations to run on various types of form inputs
-
Utilities - various other functions
-
Installation
Run npm i @arc-core-components/feature_subscriptions@stable
to add it to your project.
In your default output file, add a script that sets window.arcIdentityApiOrigin
, window.arcSalesApiOrigin
, and window.arcSignInUrl
. The arcIdentityApiOrigin
and arcSalesApiOrigin
will usually point to the same location. The arcSignInUrl
should point to a page or template where you have implemented your signin feature.
For example here is a partial snippet:
// File: components/output-types/default.jsx
//set cc client side variables
let subsConfig = `window.arcIdentityApiOrigin = "YOUR_API_ORIGIN_URL";`;
subsConfig += `window.arcSalesApiOrigin = "YOUR_API_ORIGIN_URL";`;
subsConfig += `window.arcSignInUrl = "YOUR_SUBSCRIPTIONS_LOGIN_URL";`;
return (<html lang="en">
<head>
<script type="text/javascript" dangerouslySetInnerHTML={{ __html: subsConfig }} />
</head>
<body>
...
Identity
This allows you to use pre-built solutions for managing login/logout, lost password, user profile, viewing order history and managing subscriptions.
SPA
This is a Single Page App that has all of the pre-configured workflow already setup and ready for you to customize and start using.
Property | Type | Description |
---|---|---|
config (required) | Object | Configurations for the SPA |
debug | Boolean | Toggle debugging messages inside of the SPA |
localization | Object | Object with mappings to all the text, error codes and country codes so you can customize all text within the SPA |
styles | Object | Object with mappings to all styles so you can customize the look and feel of the SPA |
SPA Configuration
These are passed to the config property and will affect how your SPA works.
Property | Type | Description |
---|---|---|
dateFormat | String | Accepts EU or US
|
useCookies | Boolean | Whether or not to allow cookies (if disabled uses localstorage instead) |
autoLogin | Boolean | If true will automatically login after creating a new account |
secondLastName | Boolean | If true, displays a second last name field on the sign up and profile form |
enableMagicLink | Boolean | Toggles showing the magic link button on the forgot password form |
recaptcha | Object | Developer configuration settings for ReCaptcha |
debug | Boolean | When true will console log debugging messages |
termsUrl | String | Url to your terms of service |
privacyUrl | String | Url to your privacy policy |
GDPRUrl | String | Url to GDPR policies |
registerUrl | String | Url to create a new account |
signInUrl | String | Url to sign in |
signOutUrl | String | Url to sign out page |
signOutPageHomeUrl | String | Url to return to the home page once you've signed out |
signOutPageSignInUrl | String | Url on the sign out page to sign in again |
signOutPageSignUpUrl | String | Url on the sign out page to create a new account |
profileUrl | String | Url to the user's profile page |
useTermsModal | Boolean | If true, shows the terms of service in a modal window rather than a clickable URL |
isTermsModalOpen | Boolean | Function |
termsModalHideCloseIcon | Boolean | Whether or not to hide the terms of service close modal icon |
termsModalChildren | Object | Content to display in the terms of service modal |
showSignOutLink | Boolean | Whether or not to show the sign out link on the profile |
hidePrivacyModalCloseIcon | Boolean | Whether or not to display the close modal icon in the privacy modal |
googleButtonWidth | Number | The width of the google social sign in button |
googleButtonHeight | Number | The height of the google social sign in button |
googleButtonLongTitle | Boolean | Whether or not to use the short title or the long title on the google social sign in button |
googleButtonTheme | String | The theme for the google button, defaults to "dark" |
fbButtonSize | String | The size of the facebook button |
fbButtonType | String | The type of facebook button |
fbIncludePicture | Boolean | Whether or not to include a picture on the facebook button |
dobRegistration | Boolean | Turn on requirements to be a certain age before you can register |
dobRequiredRegistration | Boolean | Forces the date of birth field to be required on the registration form |
hideFacebookOnSignIn | Boolean | Hides the button to sign in with Facebook on the sign in page |
hideGoogleOnSignIn | Boolean | Hides the Google sign in button on the sign in page |
hideFacebookOnSignUp | Boolean | Hides the register with Facebook button on the registration page |
hideGoogleOnSignUp | Boolean | Hides the register with Google button on the registration page |
registrationAge | Number | Sets the age a user must be in order to create an account, use 0 (default) if any age is allowed. For example, if this value is set to 14 then users that are 14 years and 1 day old will be permitted to register, anyone younger will not. |
peekSignUpStateCallback | Function | A function intended to return the current state values to be used in defining new logic/properties outside of the sign up form, for instance setting profile attributes from selections in the privacy modal |
Hash Routes
These are the hash routes used in the Identity SPA:
#/ or #/sign-in – login to an existing account or optionally use social logins (FB or Google)
#/register – creates a new account by filling in the form or optionally using social sign up buttons (FB or Google)
#/sign-out – destroys the user’s session and gives them options on where to go next
#/profile – Includes the change password form, allows the user to edit their account information they entered when they signed up, includes the privacy modal (if enabled) and a link to sign out.
#/manage – allows a user to manage their current, update their credit card, change their billing address, cancel a subscription and view their order history.
#/forgot-password – for users who have forgotten their password.
#/verify-email?nonce={nonce} – if enabled in the subs admin, will force users to verify their email address before they can proceed to their profile page.
#/reset-password?nonce={nonce} - allows the user to reset their password if the nonce is valid.
#/magic-link?nonce={nonce} – allows the user to send themselves a one-time access link to login without having to remember their password if the nonce is valid.
SPA Sample Implementation
/* eslint-disable */
import React from 'react';
import Subscriptions from '@arc-core-components/feature_subscriptions';
/**
* @class IdentitySPA
* @desc Single page application for subscriptions Sign In, Sign Up, Profile,
* Reset Password, and Magic Link functionality
*
* @return {Object} IdentitySPA
*/
class Identity extends React.PureComponent {
/**
* Render the Identity SPA
**/
render() {
return (<Subscriptions.IdentitySPA
debug={false}
styles={{
wrapperClasses: 'col',
profilePageContainerClasses: 'width_full',
managePageContainerClasses: 'width_full',
headerClasses: '',
errorClasses: 'row color_red',
errorHeadlineSize: 4,
}}
config={{
useCookies: true,
autoLogin: true,
secondLastName: false,
recaptcha: {
enabled: true,
token: "your_site_key_here",
position: "above",
size: "invisible",
},
termsUrl: "http://my.site.com/terms",
privacyUrl: "http://my.site.com/privacy",
GDPRUrl: "http://my.site.com/gdpr",
signOutUrl: '/sign-out',
signOutPageHomeUrl: '/homepage',
signOutPageSignInUrl: '/sign-in',
signOutPageSignUpUrl: '/register',
profileUrl: '/profile',
dobRegistration: true,
dobRequiredRegistration: true,
googleButtonWidth: 400,
googleButtonHeight: 30,
registrationAge: 14,
}}
/>);
}
}
export default Identity;
SPA Localization
All text within the SPA can be localized by passing a custom localization object with alternative/translated content. For a full list of all text that can be customized please see the localization section below.
SPA Styles
By default we provide bootstrap classes on all components for you. In order to match the look and feel of your project we expose certain classes within the SPA that you can set to your existing CSS classes. For a full list of all styles that can be customized please see the styles section below.
Identity Forms
- Sign Up - Create a new account
- Sign In - Login to your existing account
- Profile - View/edit user profile
- Manage - View order history and see/cancel current subscription
- Email Verification - Allow users to verify their email address
- Forgot Password - Request a link to change the user's password
- Reset Password - Allow a verified user to set a new password
- Order History - A table to display/sort orders
- Change Password - A form for changing the user's profile after they've logged in
- Magic Link - A form to get a one time login magic link code
- Sign Out - A form to destroy the user's session and let them sign in again or create a new account
Sign Up Form
Allows a user to create a new account on your site
Property | Type | Description |
---|---|---|
useCookies (required) | Boolean | Whether or not to use cookies |
doLogin (required) | Boolean | If true, signs the user in after a successful sign up |
successUrl (required) | String | Where the user should be redirected to after a successful sign up |
headerProps | Object | Props to pass to the Header form element at the top of the profile form |
saveChangesProps | Object | Props to pass to the SaveChanges form submit button |
firstNameProps | Object | Props to pass to the FirstNameInput form element |
lastNameProps | Object | Props to pass to the LastNameInput form element |
signInButtonProps | Object | Props to pass to the SignInButton form element |
errorText | Object | Localization of all SDK API error messages |
<SignUpForm
useCookies={false}
doLogin={true}
successUrl="http://my.site.com/profile"
/>
Sign In Form
Allows a user with an existing account to login to that account
Property | Type | Description |
---|---|---|
loginSuccessUrl (required) | String | URL to redirect the user to upon successful login, defaults to /profile ) |
cookie | Boolean | Use cookies to store user authentication |
recaptchaToken | String | The ReCaptcha token |
wrapperClasses | String | Classes to apply around the sign in form |
errorClasses | String | Classes to apply to sign in form error messages |
headerProps | Object | Props to pass to the Header form element at the top of the sign up form |
emailInputProps | Object | Props to pass to the EmailInput form element |
passwordInputProps | Object | Props to pass to the PasswordInput form element |
forgottenPasswordLinkProps | Object | Props to pass to the ForgotPasswordLink form element |
signInButtonProps | Object | Props to pass to the SignInButton form element |
rememberMeCheckboxProps | Object | Props to pass to the RememberMeCheckbox form element |
errorText | Object | Localization of all text and error codes |
<SignInForm
loginSuccessUrl="http://my.site.com/profile"
/>
Profile Form
Allows a user to view and edit their profile information
Property | Type | Description |
---|---|---|
wrapperClasses | String | the classes to use on around form elements |
headerProps | Object | properties to pass to the Header form element |
firstNameProps | Object | properties to customize the FirstNameInput element |
lastNameProps | Object | properties to customize the LastNameInput element |
secondLastNameProps | Object | properties to customize the SecondLastNameInput element |
displayNameProps | Object | properties to customize the DisplayName element |
emailInputProps | Object | properties to customize the EmailInput element |
DOBInputProps | Object | properties to customize the DOBInput element |
genderRadioButtonsProps | Object | properties to customize the GenderRadioButtons element |
addressContainerProps | Object | properties to customize the AddressContainer element |
validateFullAddressCallback | Function | custom function that validates the address |
saveChangesButtonProps | Object | properties to customize the SaveChangesButton element |
errorClasses | String | the classes applied to the error messages displayed in case of failure |
successClasses | String | the classes applied to the success messages displayed in case of success |
errorText | Object | Localization of all SDK API error messages |
successText | Object | Localization of all SDK API success messages |
getProfileFailureUrl | String | the url to redirect the user in case of failure to retrieve the user profile |
requireEmailVerification | Boolean | the condition of requiring the user to verify their email address before accessing their profile information (defaults to false) |
verifyEmailUrl | String | the url to redirect the user in the case that the email is not verified |
<ProfilePageForm
headerProps={{
title: "Profile Page",
}}
DOBInputProps={{
dateFormat: "US",
}}
getProfileFailureUrl="http://my.site.com/login"
verifyEmailUrl="http://my.site.com/verify-email"
/>
Manage Form
Allows a user to view and/or cancel their subscription and see their latest order history
Property | Type | Description |
---|---|---|
localization (required) | Object | Object containing all localization values passed from the SPA |
styles | Object | Object containing all style customization prop values |
<ManageSubsPage
localization={localizationObject}
styles={stylesObject}
/>
Email Verification Form
Allows a user to verify they are using a valid email address.
Property | Type | Description |
---|---|---|
successUrl | String | Redirect to this URL on successful verification |
successText | String | Message to display on successful verification |
nonce | String | A nonce to verify the email through the user's email provider |
<EmailVerification
successUrl="/#profile"
/>
How To Verify An Email Address
When you set the verify email address flag to true in the Subs admin the IdentitySPA and the Login Form will require a verified email addresses before the user can login and view their profile or manage their subscription. Upon account creation an email must be set to the user's unverified email address and include a link back to the following URL pattern in order to complete the full verification process: https://my.site.com/{subscriptions-url}?nonce={nonce}/#verify
Forgot Password Form
Allows a user to request a link to reset their password
Property | Type | Description |
---|---|---|
header | String | the forgot password header text |
instructions | String | instructions on how to fill out the form to get a reset password link |
emailInputProps | Object | properties to pass to the EmailInput form element |
resetLinkButtonProps | Object | properties to pass to the ResetLinkButton form element |
magicLinkButtonProps | Object | properties to pass to the MagicLinkButton form element |
wrapperClasses | String | classes wrapper around form |
instructionClasses | String | classes that wrap around the instructions for this form |
errorClasses | String | classes for error messages |
successClasses | String | classes for success messages |
defaultResponseText | Object | an object with all default text, error codes and response messages to override the default values |
<ForgotPasswordForm
header="Forgot Your Password?"
instructions="Enter your email address and click the button to send a reset password link to your email"
/>
Reset Password Form
Allows a user to reset their password. Requires an email be sent to the user with a nonce in the format of https://my.site.com/{subscriptions-url}?nonce={nonce}/#reset-password
React Prop | Type | Description |
---|---|---|
successUrl (required) | String | Where the user is redirected after they successfully change their password |
nonce | String | optional nonce to use in place of the nonce coming from the window URL hash |
header | String | the forgot password header text |
loading | String | message to display while the component is loading |
wrapperClasses | String | classes wrapper around form |
loadingClasses | String | properties to pass to the EmailInput form element |
headerClasses | String | classes to pass to the header |
passwordProps | Object | properties to pass to the first password input |
confirmPasswordProps | Object | properties to pass to the second confirm password input |
resetButtonProps | Object | properties to pass to the reset password button at the bottom of the form |
instructionClasses | String | classes that wrap around the instructions for this form |
errorClasses | String | classes for error messages |
successClasses | String | classes for success messages |
defaultText | Object | an object with all default text, error codes and response messages to override the default values |
<ResetPasswordForm
successUrl="http://my.site.com/login"
/>
Manage Subscriptions Status Bar
Property | Type | Description |
---|---|---|
statusLabel | String, JSX Element | Status Label |
statusInputPlaceholder | String | Status Input Placeholder |
statusRenderInputContent | Function | Status Render Input Content |
actionLabel | String, JSX Element | Action Label |
actionInputPlaceholder | String | Action Input Placeholder |
actionCancelReasons | Array | Action Cancel Reason Options List |
actionBarCancelSubscriptionButtonContent | String, JSX Element | Action Bar Cancel Subscription Button Content |
actionBarSubmitButtonContent | String, JSX Element | Action Bar Submit Button Content |
actionBarCancelButtonContent | String, JSX Element | Action Bar Cancel Button Content |
actionBarRenewSubscriptionButtonContent | String, JSX Element | Action Bar Renew Subscription Button Content |
actionBarRenewSubscriptionRenderLabelContent | Function | Action Bar Renew Subscription Render Label Content |
actionBarShowSubscriptionsButtonContent | String, JSX Element | Action Bar Show Subscriptions Button Content |
actionBarShowSubscriptionsLabelContent | String, JSX Element | Action Bar Show Subscriptions Label Content |
actionAlertSuccessContent | String, JSX Element | Action Alert Success Content |
actionAlertErrorContent | String, JSX Element | Action Alert Error Content |
actionAlertDuration | Number | Action Alert Duration |
loadingIndicator | String, JSX Element | Loading Indicator |
renewSubscriptionCampaignID | String, Number | "Renew Subscription" CampaignID |
showSubscriptionsCampaignID | String, Number | "Show Subscription" CampaignID |
renewSubscriptionURL | String | Renew Subscription URL |
showSubscriptionOptionsURL | String | Show Subscription Options URL |
styles | Object | Object containing all custom class and styling props |
<ManageSubStatusBar
statusLabel="Current Subscription"
statusInputPlaceholder=""
statusRenderInputContent={subObj => `${subObj.productName} - ${subObj.subscriptionID}`}
actionLabel="Reason for Cancellation"
actionInputPlaceholder="Select reason..."
actionCancelReasons={[
"Price is too expensive"
"Didn't utilize my subscription enough"
"Found a service I like better"
"I just don't want it anymore"
]}
actionBarCancelSubscriptionButtonContent="Cancel Subscription"
actionBarSubmitButtonContent="Submit & Cancel"
actionBarCancelButtonContent="Nevermind"
actionBarRenewSubscriptionButtonContent="Renew subscription"
actionBarRenewSubscriptionRenderLabelContent={(subObj) => {
return (<><i className="mr-2">{subObj.productName}</i>subscription has expired</>);
}}
actionBarShowSubscriptionsButtonContent="Show subscription options"
actionBarShowSubscriptionsLabelContent={(<i className="mr-2">No current subscriptions</i>)}
actionAlertSuccessContent="Subscription Cancellation Successful!"
actionAlertErrorContent="Subscription Cancellation Failed"
actionAlertDuration={4000}
loadingIndicator={(<div className="alert alert-warning">Loading data...</div>)}
renewSubscriptionCampaignID={12345}
showSubscriptionsCampaignID={67890}
renewSubscriptionURL="/packages-feature-subscriptions-src-children-retail-spa-spa#/campaign"
showSubscriptionOptionsURL="/packages-feature-subscriptions-src-children-retail-spa-spa#/campaign"
styles={stylesObject}
/>
Order History Table
Creates a responsive, sortable table of the user's order history with expandable rows for overflowing fields (dynamic/responsive)
Property | Type | Description |
---|---|---|
title | String | Title to use on the table |
displayConfig | Function | Function that returns a configuration object used for providing table display parameters to child Table component |
styles | Object | Object containing all custom class and styling props |
<OrderHistoryTable
title="Table Title"
styles={stylesObject}
displayConfig={displayType => ({
mobile: {
numColumns: 2,
displayClasses: `d-${displayType} d-sm-${displayType}`,
hiddenClasses: "d-none d-sm-none",
},
tablet: {
numColumns: 3,
displayClasses: `d-md-${displayType}`,
hiddenClasses: "d-md-none",
},
desktop: {
numColumns: 5,
displayClasses: `d-lg-${displayType} d-xl-${displayType}`,
hiddenClasses: "d-lg-none .d-xl-none",
},
})}
/>
Change Password Form
This allows a user to change their password to their account. They must already be signed into their account in order to use this form.
Property | Type | Description |
---|---|---|
header | String | Title shown above the form |
headerClasses | String | Classes to apply to the header text |
loading | String | Text to display for the loading message |
loadingClasses | String | Classes to apply to the loading text |
wrapperClasses | String | Classes to apply to the div around the form |
errorClasses | String | Classes to apply to the error messages return from the form |
successClasses | String | Classes to apply to the success messages return from the form |
oldPasswordProps | Object | Values passed to the passwordInput component used for the old password input field |
newPasswordProps | Object | Values passed to the passwordInput component used for the new password input field |
confirmPasswordProps | Object | Values passed to the passwordInput component used for the confirm password input field |
saveChangesButtonProps | Object | Values passed to the button component used to save changes |
defaultText | Object | Localzation of text and error codes |
<ChangePassword
loading="Loading, please wait..."
successClasses: "text-success mb-2",
newPasswordProps: {{
label: "Enter Your New Password",
}}
/>
Magic Link Form
This allows a user to request a one time access code to login to their account if they've forgotten their password. It requires a nonce be sent to them with a link to their email address in the format of https://my.site.com/{subscriptions-url}?nonce={nonce}/#magic-link
React Prop | Type | Description |
---|---|---|
wrapperClass | String | Classes applied to the wrapper div |
successUrl | String | The url to redirect to when a successful nonce is verified |
successText | String | The text to show when a nonce is successfully verified |
nonce | String | The nonce to verify (will check from the URL by default but can also be passed as a prop) |
<MagicLinkForm />
Sign Out Form
When a user is logged in and this form is rendered this form will automatically clear their session and display options to allow them to log back in, create a new account, or go back to the homepage.
React Prop | Type | Description |
---|---|---|
pageText | String | Text to show above the links on the page |
wrapperClasses | String | Classes to apply to the wrapper div |
textClasses | String | Classes to apply to the text at the top of the sign out form |
homeText | String | The text for the home url link |
homeUrl | String | The url for redirecting the user back to the homepage |
redirectLinkHomeClasses | String | Classes to apply to the homepage redirect link |
signInText | String | The text for the sign in url link |
signInUrl | String | The url for redirecting the user to the sign in page |
redirectLinkSignInClasses | String | Classes to apply to the sign in url |
signUpText | String | The text for the sign up url link |
signUpUrl | String | The url for redirecting the user to the sign up page |
redirectLinkSignUpClasses | String | Classes to apply to the sign up url |
<SignOutForm
pageText="You have successfully logged out!"
/>
Google Sign On
Creates an out-of-the-box Sign On with Google
feature.
Required Setup
- The correct google ID must be setup in the Subs Admin for the particular tenant (apiOrigin).
- The component must be placed on a valid https page. (For local development ngrok was used).
React Prop | Type | Description |
---|---|---|
config | Object | the object containing all the configurations for the GoogleSignOn feature. |
styles | Object | the object containing all the styling classes for the GoogleSignOn feature. |
text | Object | the object containing all the error messages for the Google Sign On Feature |
redirectLink | String | the url to which the user gets redirected after a successful Google sign on. |
googleButtonWidth | Number | width in pixels accepted by the Google Sdk (Defaults to 120). |
googleButtonHeight | Number | height in pixels accepted by the Google Sdk (Defaults to 36). |
googleButtonLongTitle | Boolean | boolean value that sets whether to display long labels such as "Sign in with Google" rather than "Sign in" (Defaults to false). |
googleButtonTheme | String | The color theme of the button: either light or dark (defaults to "light"). |
wrapperClasses | String | classes to style the button wrapper |
sdkErrorClasses | String | classes to style the error message in case the google sdk fails to load. |
signOnErrorClasses | String | classes to style the error message in case the google Sign in fails. |
successCallback | Function | function that is invoked after a succesful sign on |
failureCallback | Function | function that is invoked after a failed sign on |
attemptCallback | Function | function that is invoked after the button click |
sdkErrorMessage | String | error message to be displayed in case the Google sdk fails to load |
signOnErrorMessage | String | error message to be displayed in case the Google sign on fails for any reason |
Additional Customizations
More Google button customization options are available on https://developers.google.com/identity/sign-in/web/reference#ui_elements
<GoogleSignOn
config= {{
redirectLink: "/profile",
googleButtonWidth: 400,
googleButtonHeight: 40,
googleButtonLongTitle: true,
googleButtonTheme: "dark",
}}
styles={{
wrapperClasses: "d-flex flex-column align-items-center justify-content-center mt-3",
sdkErrorClasses: "text-danger",
signOnErrorClasses: "text-danger",
}}
/>
Facebook Sign On
Creates an out-of-the-box Sign On with Facebook
feature.
Required Setup
- The correct facebook APP ID and App Secret must be setup in the Subs Admin for the particular tenant (apiOrigin).
- The component must be placed on a valid https page. (For local development ngrok was used).
React Prop | Type | Description |
---|---|---|
config | Object | the object containing all the configurations for the FacebookSignOn feature. |
styles | Object | the object containing all the styling classes for the FacebookSignOn feature. |
text | Object | the object containing all the error messages for the FacebookSignOn Feature |
redirect | String | the url to which the user gets redirected after a successful facebook sign on. |
fbButtonSize | String | the size of the button configured by the facebook sdk, can be "large", "medium" or "small". Defaults to "large". |
fbButtonType | String | the button text accepted by the facebook sdk, must be either "login_with" or "continue_with". Defaults to "login_with". |
fbIncludePicture | Boolean | a boolean value accepted by the facebook sdk that allows the component to either include the name and profile picture when the user is signed into Facebook or not. |
wrapperClasses | String | classes to style the button wrapper |
sdkErrorClasses | String | classes to style the error message in case the Facebook sdk fails to load. |
signOnErrorClasses | String | classes to style the error message in case the Facebook Sign On fails. |
successCallback | Function | function that is invoked after a succesful sign on |
failureCallback | Function | function that is invoked after a failed sign on |
attemptCallback | Function | function that is invoked after the button click |
sdkErrorMessage | String | error message to be displayed in case the Facebook sdk fails to load |
signOnErrorMessage | String | error message to be displayed in case the Facebook Sign On fails for any reason |
<FacebookSignOn
config={{
fbButtonSize: "medium",
fbButtonType: "continue_with",
}}
styles={{
wrapperClasses: "border border-success d-flex justify-content-center"
}}
/>
Retail & Sales
This allows you to use pre-built solutions for managing campaigns, displaying products, adding/removing items to your cart, payment processing and confirmation of your purchases.
SPA Configuration
This is a Single Page App that has all of the pre-configured workflow already setup and ready for you to customize and start using.
Property | Type | Description |
---|---|---|
useCookies (required) | Boolean | Whether or not to use cookies |
autoLogin | Boolean | Automatically login via a cookie or local storage |
checkoutUrl | String | Hash fragment used when user selects an offer |
loginUrl | String | Hash fragment used when user needs to login |
addItemToCartFailureUrl | String | Hash fragment used when we encounter an error adding an item to the cart |
confirmationPageRedirectLinkURL | String | Hash fragment used when user clicks the "Start Reading" button on the confirmation page |
errorUrl | String | Hash fragment used when an error is encountered |
confirmUrl | String | Hash fragment used when user has paid |
offersUrl | String | Hash fragment used when the user is looking at offers |
recaptcha (required) | Object | Config for recaptcha |
registerUrl | String | Hash fragment used when user wants to create a new account |
Hash Routes
These are the hash routes used in the retail SPA:
#/ and #/campaign – This pulls up the campaign to display the products and subscriptions available for purchase. This uses data from a content source.
#/checkout – This displays the items currently in the user’s shopping cart.
#/confirmation – This displays a confirmation message after the payment has been successfully processed by the payment processor.
#/error – This is the default error message if something has gone wrong at any point during this process.
SPA Sample Usage
This will create the retail spa with debugging messages.
import Subscriptions from '@arc-core-components/feature_subscriptions';
<Subscriptions.RetailSPA
debug={true}
styles={this.props.styles}
config={this.props.configuration}
localization={this.props.translatedMessages}
offersData={this.props.offers}
/>
SPA Localization
All text within the SPA can be localized by passing a custom localization object with alternative/translated content. For a full list of all text that can be customized please see the localization section below.
SPA Styles
By default we provide bootstrap classes on all components for you. In order to match the look and feel of your project we expose certain classes within the SPA that you can set to your existing CSS classes. For a full list of all styles that can be customized please see the styles section below.
Retail Forms
- Campaign - displays a list of the current products in a campaign
- Cart - displays a list of items in the user's shopping cart along with
Campaign Form
Allows a user to view the information related to a campaign in form of a headline image, headline text and one or several products. If a product contains several rates, the user has the option to select one, the product then being added to the user cart.
Property | Type | Description |
---|---|---|
offersObject (required) | Object | The object that contains all the offer related information that has been set up in the Subscriptions Admin |
productCardsContainerProps | Object | Properties (text and styles) applied to the productCardsContainer element |
headlineImageProps | Object | Properties (text and styles) applied to the HeadlineImage element |
disclaimerMessageProps | Object | Properties (text and styles) applied to the Header (Disclaimer Message) component |
checkoutUrl | String | The url of the checkout page where the user is able to interact with the current contents of their cart |
loginUrl | String | The url of the login page where the user can either login or register and then proceed to checkout without losing the contents of their cart |
addItemToCartFailureUrl | String | The url of the page on which the user lands in case the add to cart process fails |
<Subscriptions.Campaign
checkoutUrl= "/checkout"
loginUrl= "/login"
addItemToCartFailureUrl= "/404"
headlineImageProps={{
wrapperClasses: String
wrapperStyles: Object,
smBrkPnt: String,
mdBrkPnt: String,
pageTitleSize: Number,
titleClasses: String,
pageSubTitleSize: Number,
subTitleClasses: String,
}}
productCardsContainerProps= {{
cardsWrapper: String,
productCardsProps: {
wrapperClasses: String,
headerProps: {
className: String,
},
unorderedListProps: {
wrapperClasses: String,
itemClasses: String,
},
getOfferButtonProps: {
className: String,
},
lazyLoadingImageProps: {
wrapperClasses: String,
imageSrc: String,
imageAlt: String,
imageClasses: String,
loaderSrc: String,
loaderAlt: String,
loaderClasses: String,
},
productPriceRadioButtonsProps: {
wrapperClasses: String,
label: String,
labelClasses: String,
radioContainerClasses: String,
},
singleProductPriceFieldProps: {
size: Number,
className: String,
},
},
}}
disclaimerMessageProps= {{
size: Number,
children: String,
className: String,
}}
offersObject= {OFFERS_OBJECT}
/>
OFFERS_OBJECT
Notes on the In the current implementation with Fusion, the offers object is returned by making an api call that uses the campaign-name as a URI parameter, which is editable via a custom field.
A resolver needs to be setup in the sources
folder, that would handle the API assembly logic.
const resolve = (params) => {
const website = params['my-site'];
const { 'campaign-name' } = params;
return `https://api-${org}-${website}.cdn.arcpublishing.com/retail/public/v1/offer/live/${campaign-name}`;
};
export default {
resolve,
params,
};
The resolver can then be called inside the feature, passing the returned offers object to the Campaign component as a property.
...
const { cached, fetched } = this.getContent('offers', { campaignName: props.customFields.defaultCampaign });
this.state = { offers: cached };
fetched.then((offers) => {
this.setState({ offers });
});
...
...
...
render(){
return(
<Subscriptions.Campaign
...
...
offersObject= {this.state.offers}
/>
)
}
...
Cart Form
This will quickly create a cart that displays a user's items they are trying to purchase, allows them to remove items, and provides a summary for the cost of those items.
Property | Type | Description |
---|---|---|
config (required) | Object | An object containing the cart's configuration |
localization | Object | An object that includes the default text and error messages for the cart |
styles | Object | An object with style classes |
import Subscriptions from '@arc-core-components/feature_subscriptions';
<Subscriptions.Cart />
Paywall
The paywall is comprised of two parts:
-
A portal component that loads the paywall script (p.js) and runs it to check the user's registration status.
-
A modal with contents, buttons, links etc wrapped by the portal.
If you want the prebuilt modal contents you can pass a PaywallModal component into the PaywallPortal. Otherwise pass in your own children if you need something more flexible. It's pretty barebones so this will most likely happen.
Paywall Domains
- apiOrigin and paywallScriptSrc should look like the following:
-
"paywallScriptSrc": "https://my.site.cdn.arcpublishing.com/arc/subs/p.js"
-
"paywallApiOrigin": "//api-my.site.cdn.arcpublishing.com"
-
If you add https:// to the paywallApiOrigin ArcP which is the paywall script adds https twice, it will break.
-
The domain of paywallScriptSrc and paywallApiOrigin have to be the same, if they're not you get a CORS error and you'll get an error that the entitlement check failed (this is an under the hood request ArcP makes to the sales api to determine user registration).
-
You will need versions of these url's for both sandbox and production. It's best to keep them in site properties for each of your sites.
Paywall p.js Script (ArcP)
-
This will be located at https://my.site.cdn.arcpublishing.com/arc/subs/p.js
-
If it's not available you will need to have it provisioned by the Arc Delivery team (DEL - minimum 1 week lead time).
-
The p.js script is generated when you activate a paywall in the subs admin. Only one paywall can be active at a time. When you activate a new paywall you will get a new p.js. If you don't and the rules aren't updating when you run ArcP on the frontend, contact arc subscriptions support.
-
You can type ArcP into the browser console to make sure the p.js script loaded (loaded by PaywallPortal via the paywallScriptSrc) properly.
-
You can furthermore type ArcP._facts or ArcP._rules to see what facts were collected about the user and which paywall ruleset is being loaded from the admin. The _facts and _rules are compared by p.js to determine if the paywall should be triggered or not. If the paywall is triggered the modal will appear, and then the callback you entered thru the paywallFunction prop will also fire. You can also pass in the resultsCallback prop if you want anything else to happen after ArcP runs regardless whether the paywall is triggered or not as a follow up.
Setting Up A The Paywall In Fusion
Create a wrapper component and collect the necessary props the paywall needs for ArcP to run including:
-
paywallScriptSrc - the source of your p.js file
-
contentType - from globalContents - from the type field
-
contentSection - from globalContents - see below, it should come from the websites field
-
contentId - from globalContents - either the source id or the canonical_url
-
Without the above props ArcP cannot function
PaywallPortal Props
React Prop | Type | Description |
---|---|---|
paywallScriptId (required) | String | A unique id for the p.js script tag. |
paywallScriptSrc (required) | String | A src url to get p.js from the cdn. |
contentType (required) | String | from globalContents - from the type field. |
contentSection (required) | String | from globalContents - see below, it should come from the websites field. |
contentId (required) | String | from globalContents - either the source id or the canonical_url. |
paywallFunction | Function | Whatever you want to happen when ArcP triggers the paywall. The modal always pops up regardless of what function you pass in here. |
customSubCheck | Function | Passed to ArcP if you want to override the default subscription status check. |
customRegCheck | Function | Passed to ArcP if you want to override the default logged in status check. |
resultsCallback | Function | Whatever you want to happen after ArcP.run returns. |
children | Elements | You can pass in your own child elements instead of the contents of PaywallModal. |
PaywallPortal Configuration
Example of how to setup the PaywallPortal with premade PayallModal contents and the IconButton (X button):
import Subscriptions from '@arc-core-components/feature_subscriptions';
<Subscriptions.PaywallPortal
overlayClassName="modal-dialog"
contentClassName="modal-content modal-body"
paywallScriptId="pjs-script"
paywallScriptSrc="https://my.site.cdn.arcpublishing.com/arc/subs/p.js"
contentType="your-content-type"
contentSection="your-content-section"
contentId="your-story-content-id"
>
<Subscriptions.IconButton
iconClassName="close"
onClickHandler={
() => (
window.location.href = 'your-close-modal-redirect-location'
)
}
keyString="Escape"
>
<span>×</span>
</Subscriptions.IconButton>
<Subscriptions.PaywallModal
styles={
{
paywallModalHeaderClassName: "",
paywallModalHeaderSize: 2,
paywallModalSubheaderClassName: "",
paywallModalDescriptionClassName: "",
paywallModalOfferClassName: "",
paywallModalAllOffersClassName: "",
paywallModalSignInClassName: "",
paywallModalSignInMessageClassName: "",
}
}
text={
{
paywallModalHeaderText: "Welcome to the PayWall",
paywallModalSubheaderText: "You are out of free stories.",
paywallModalDescriptionText: "Subscribe for $25 per month.",
paywallModalOfferText: "Subscribe",
paywallModalAllOffersText: "See all offers",
paywallModalSignInText: "Sign In.",
paywallModalSignInMessageText: "Already have an account? ",
}
}
links={
{
paywallModalOfferUrl: "your-retail-SPA-url/#campaign?code=your-campaign-code",
paywallModalAllOffersUrl: "your-default-offer-retail-SPA-url/#campaign",
paywallModalSignInUrl: "your-identity-SPA-url/#sign-in",
}
}
>
</Subscriptions.PaywallModal>
</Subscriptions.PaywallPortal>
Example Paywall Component
This is an example of an implementation of a paywall component in a fusion feature pack repository. It should be added to all article templates and pages that should trigger a paywall.
import React, { PureComponent } from 'react';
import Subscriptions from '@arc-core-components/feature_subscriptions';
import PropTypes from 'fusion:prop-types';
import Consumer from 'fusion:consumer';
/**
* We don't ever want to render the paywall server side
* so we can use this function to make sure we exit the
* render loop if this is a server side render
**/
function isServerSide() {
return typeof window === 'undefined';
}
@Consumer
class Paywall extends PureComponent {
/**
* Handle the redirect back to a page that doesn't need
* a subscription when they close the paywall modal
**/
handleRedirect = () => {
const {
customFields: {
paywallIconButtonUrl,
},
} = this.props;
window.location.href = paywallIconButtonUrl;
};
/**
* This is the logic (or something similar) you'll need to implement
* in order to remove or hide the article body from the DOM when the
* paywall is triggered
**/
hideArticleBody = () => {
alert('TODO: update hide article body logic');
/* if (document.querySelector('your_article_body_parent_class') && document.querySelector('your_article_body_class')
&& !this.props.isAdmin) {
const article = document.querySelector('your_article_body_parent_class');
const body = document.querySelector('your_article_body_class');
article.removeChild(body);
} */
}
/**
* Our recommendation is that you display the modal inline when you are in PB admin
* to prevent it from covering content on your page. This applies to the modal overlay.
**/
getModalOverlayClasses = (isAdmin) => {
return isAdmin ? 'background_gray flex align_items_center justify_center'
: 'fullscreen fixed background_gray flex align_items_center justify_center z_index_highest';
}
/**
* Our recommendation is that you display the modal inline when you are in PB admin
* to prevent it from covering content on your page. This applies to the content in the modal.
**/
getModalContentClasses = (isAdmin) => {
return isAdmin ? 'flex container_column justify_space_between background_white paywall paywall-modal_container'
: 'flex container_column justify_space_between background_white paywall paywall-modal_container relative';
}
/**
* Render the paywall component
*/
render() {
const { arcSite, isAdmin } = this.props;
const { paywallScriptSrc } = getProperties()[arcSite]; // or wherever this is defined in your site properties JSON files
const {
_id: contentId,
type: contentType,
} = this.props.globalContent;
const {
websites: {
[arcSite]: {
website_section: {
_id: sectionId,
},
},
},
} = this.props.globalContent;
const modalOverlayClasses = this.getModalOverlayClasses(isAdmin);
const modalContentClasses = this.getModalContentClasses(isAdmin);
const iconClassName = 'modal_icon pointer absolute';
const iconKeyString = 'Escape';
const paywallScriptId = 'pjsscript';
const paywallModalHeaderClassName = 'paywall-modal_header';
const paywallModalSubheaderClassName = 'paywall-modal_sub-header';
const paywallModalDescriptionClassName = '';
const paywallModalOfferClassName = 'button button_primary';
const paywallModalAllOffersClassName = '';
const paywallModalSignInMessageClassName = '';
const paywallModalSignInClassName = '';
const paywallModalSignUpMessageClassName = '';
const paywallModalSignUpClassName = '';
const {
customFields: {
paywallModalHeaderText,
paywallModalSubheaderText,
paywallModalDescriptionText,
paywallModalOfferText,
paywallModalAllOffersText,
paywallModalSignInText,
paywallModalSignInMessageText,
paywallModalOfferUrl,
paywallModalAllOffersUrl,
paywallModalSignInUrl,
paywallModalSignUpMessageText,
paywallModalSignUpUrl,
paywallModalSignUpText,
},
} = this.props;
return !paywallScriptSrc || isServerSide() ? null : (
<Subscriptions.PaywallPortal
overlayClassName={modalOverlayClasses}
contentClassName={modalContentClasses}
paywallScriptId={paywallScriptId}
paywallScriptSrc={paywallScriptSrc}
contentId={contentId}
contentType={contentType}
contentSection={sectionId}
paywallFunction={this.hideArticleBody}
>
<Subscriptions.IconButton
iconClassName={iconClassName}
onClickHandler={this.handleRedirect}
keyString={iconKeyString}
>
<span>×</span>
</Subscriptions.IconButton>
<p
className={paywallModalHeaderClassName}
>
{paywallModalHeaderText}
</p>
<p
className={paywallModalSubheaderClassName}
>
{paywallModalSubheaderText}
</p>
<p
className={paywallModalDescriptionClassName}
>
{paywallModalDescriptionText}
</p>
<a
href={paywallModalOfferUrl}
className={paywallModalOfferClassName}
>
{paywallModalOfferText}
</a>
<p className="text text_align_center">
<a
href={paywallModalAllOffersUrl}
className={paywallModalAllOffersClassName}
>
{paywallModalAllOffersText}
</a>
</p>
<div className="text text_align_center margin_center">
<p
className={paywallModalSignInMessageClassName}
>
{paywallModalSignInMessageText}
<a
href={paywallModalSignInUrl}
className={paywallModalSignInClassName}
>
{paywallModalSignInText}
</a>
</p>
<p
className={paywallModalSignUpMessageClassName}
>
{paywallModalSignUpMessageText}
<a
href={paywallModalSignUpUrl}
className={paywallModalSignUpClassName}
>
{paywallModalSignUpText}
</a>
</p>
</div>
</Subscriptions.PaywallPortal>
);
}
}
Paywall.propTypes = {
arcSite: PropTypes.string,
isAdmin: PropTypes.boolean,
globalContent: PropTypes.object,
customFields: PropTypes.shape({
paywallModalHeaderText: PropTypes.string.tag({
defaultValue: 'Subscribe to Keep Reading.',
name: 'Header',
}),
paywallModalSubheaderText: PropTypes.string.tag({
defaultValue: 'You do not have any free stories left this month.',
name: 'Subheader',
}),
paywallModalDescriptionText: PropTypes.string.tag({
defaultValue: 'Enjoy unlimited access with your subscription.',
name: 'Offer Description',
}),
paywallModalOfferText: PropTypes.string.tag({
defaultValue: 'Upgrade',
name: 'Link to Offer Text',
}),
paywallModalAllOffersText: PropTypes.string.tag({
defaultValue: 'See all subscription options.',
name: 'Link to All Offers Text',
}),
paywallModalSignInText: PropTypes.string.tag({
defaultValue: 'Sign In.',
name: 'Link to Sign In Text',
}),
paywallModalSignInMessageText: PropTypes.string.tag({
defaultValue: 'I have an account. ',
name: 'I Have An Account Text',
}),
paywallModalOfferUrl: PropTypes.string.tag({
defaultValue: '/',
name: 'URL To Offer Page',
}),
paywallModalAllOffersUrl: PropTypes.string.tag({
defaultValue: '/',
name: 'URL To ALL Offers Page',
}),
paywallModalSignInUrl: PropTypes.string.tag({
defaultValue: '/',
name: 'URL To Sign In Page',
}),
paywallIconButtonUrl: PropTypes.string.tag({
defaultValue: '/',
name: 'Close Button Redirect URL',
}),
paywallModalSignUpMessageText: PropTypes.string.tag({
defaultValue: 'Your first time here? ',
name: 'Sign Up Text',
}),
paywallModalSignUpText: PropTypes.string.tag({
defaultValue: 'Create an Account.',
name: 'Sign Up Link Text',
}),
paywallModalSignUpUrl: PropTypes.string.tag({
defaultValue: '/subscription#register',
name: 'Sign Up URL',
}),
}),
};
export default Paywall;
Form Elements
Element | Description |
---|---|
addressContainer | Contains all the fields needed to collect address information from a users |
alreadyASubscriber | Link for users to click on if they are already a subscriber |
button | A baseline (empty) button that can be extended or customized |
buttonOptions | A group of up to 3 buttons that display different options |
cartEmpty | A component to display an empty cart |
cartItem | Displays a single item in a cart |
cartSummary | Displays a summary of the items in the cart |
checkbox | A single form input of type checkbox |
checkoutButton | A button for checking out your cart |
cityInput | An address field for the city a user lives in |
confirmPasswordInput | A password input field for confirming your password |
countryDropdown | A dropdown address box for selecting the country a user lives in |
displayNameInput | An input field for entering a user's display name |
DOBInput | A input field for entering a user's date of birth (accepts US or EU date formats) |
dropdown | A baseline (empty) dropdown that can be extended or customized |
emailInput | An input field for entering the user's an email address |
firstAddressInput | An address input field for entering the first line of a user's address |
firstNameInput | An input field for entering the user's first name |
forgotPasswordLink | A link to direct users to the lost password form |
GenderRadioButtons | Radio buttons for a user to select their gender preference |
getOfferButton | A button to accept a campaign offer/product |
header | Creates a custom h# header |
headlineImage | A responsive image that is intended for use on the top of the campaign page or for a large image |
iconButton | A button with an SVG icon in it |
input | A baseline (empty) input field that can be extended or customized |
keepReadingButton | A button to keep reading from where the user left off |
lastNameInput | An input for entering a user's last name |
lazyLoadingImage | Loads an image using a lazy loader |
manageSubscriptionsButton | A button you can click to manage your subscription |
manageSubStatusBar | A status bar for managing subscriptions |
modal | A modal popup window |
notLoggedIn | A message to show when the user is not logged in |
passwordInput | An input field that accepts a user's password |
phoneNumberInput | An input field that accepts a user's phone number |
postalCodeInput | An address form field for entering a user's postal code |
productCard | A card for displaying information about a subscription or product |
productCardsContainer | A container that wraps all the product cards |
productPriceRadioButtons | Radio button options specifically for listing prices of a subscription or product |
radioButton | A baseline radio button input field that can be customized or extended |
redirectLink | A link that when clicked redirects the user to a different url |
rememberMeCheckbox | A checkbox for a user to click to keep a cookie/localstorage of their login credentials |
removeButton | A button to remove an item from a user's cart |
resetPasswordButton | A button to reset a user's password |
returnToCampaignLink | A link to return to a specific campaign/offers/products listing |
saveChangesButtonProps | A button for a user to save their form changes |
secondAddressInput | An address input field for entering the second line of a user's address |
secondLastNameInput | An input field for entering a second last name |
signInButton | A button to sign into a login form |
signOutButton | A button to sign out |
signUpButton | A button to sign up |
singleProductPriceField | A price field for products that don't have multiple price options |
stateInput | An address field that gives user's the option of selecting a state or region |
statusBar | A base element for a 3 tab status bar that can be customized and extended |
subscribeButton | A button that takes users to a campaign page |
table | A baseline table component that can be customized and extended |
termsAndConditions | Asks the user to agree to terms and conditions and privacy policy and GDPR requirements |
unorderedList | A baseline element for creating unordered lists, customizable and extendable |
Functions & Analytics
This section contains information about built in analytics, input validation and utility functions.
Analytics
By default all analytics are stored in window.arcAnalyticsHistoryValue
. You can alter where analytics are stored by setting window.arcAnalyticsHistoryKey = 'your_custom_analytics_key';
which would then allow you to access window.your_custom_analytics_key
to retrieve all the analytics events. In addition you can listen for the events being broadcast to catpure them in real time or you can disable analytics completely by setting window.arcAnalyticsDisabled = true;
Events
These are stored in the ANALYTIC_EVENTS object containing all analytics events.
Event | Description |
---|---|
LOGIN | Login form |
LOGOUT | Logout form |
REGISTER | Registration form |
CAMPAIGN_PAGE | Campaign/products form |
ADD_ITEM | When an item is added to the user's cart |
REMOVE_ITEM | When an item is removed from a user's cart |
PAYMENT_PAGE | Cart form |
CONFIRMATION_PAGE | Confirmation form |
PAYWALL_HIT | Activiating the paywall form |
VERIFIED_EMAIL | Attempting to verify an email |
MAGIC_LINK | Attempting to login with a magic link |
CANCEL_SUB | Attempting to cancel a subscription |
PROFILE_PAGE | When a user views the profile page |
Actions
These are stored in the ANALYTIC_ACTIONS object containing all analytics actions.
Action | Description |
---|---|
LOGIN_ATTEMPT | Attempting to login |
LOGIN_SUCCESS | Logged in successfully |
LOGIN_FAILED | Login failure or invalid username/password |
LOGOUT_SUCCESS | Logged out successfully |
LOGOUT_FAILED | Logged out failure |
REGISTER_PAGE_VIEW | Viewing the register page |
REGISTER_ATTEMPT | Attempting to create an account |
REGISTER_SUCCESS | Successfully created an account |
REGISTER_FAILED | Failed to create an account |
CAMPAIGN_PAGE_VIEW | Viewed the campaign page |
CAMPAIGN_PAGE_LEAVE | Left the campaign page |
CART_ADD_ITEM_SUCCESS | Successfully added an item to their cart |
CART_ADD_ITEM_FAILED | Failed to add an item to their cart |
CART_REMOVE_ITEM_SUCCESS | Successfully removed an item from their cart |
PAYMENT_PAGE_VIEW | Successfully viewed payment processor |
PAYMENT_SUCCESS | Completed payment with the payment processor |
PAYWALL_OPEN | When the paywall is open |
VERIFIED_EMAIL_SUCCESS | Email was successfully verified |
VERIFIED_EMAIL_FAILED | Email verification failed |
MAGIC_LINK_SUCCESS | Sucessfully logged in with a magic link |
MAGIC_LINK_FAILED | Failed to login with a magic link |
CANCEL_SUB_SUCCESS | A subscription was successfully cancelled |
CANCEL_SUB_FAILED | Subscription cancellation attempt failed |
PROFILE_PAGE_VIEW | User's profile was viewed |
PROFILE_UPDATE_SUCCESS | User's profile was successfully updated |
PROFILE_UPDATE_FAILED | User's profile update failed |
sendAnalyticEvent(event:String, action:Object)
This creates an analytics event on button press.
import Subs from '@arc-core-components/feature_subscriptions';
render () {
const { LOGIN } = Subs.ANALYTIC_EVENTS;
const { LOGIN_ATTEMPT } = Subs.ANALYTIC_ACTIONS;
return (<Subs.Button
id="loginButton"
text="Login"
callback={sendAnalyticEvent(LOGIN, { action: LOGIN_ATTEMPT }, () => {
const events = getAnalyticEventHistory();
alert(`Generated event:\n${JSON.stringify(events[events.length - 1], null, 2)}`);
})}
recaptcha={{enabled: false}}
/>);
}
sendAnalyticEventSync(event, action)
This will create an analytics event synchronously.
import Subs from '@arc-core-components/feature_subscriptions';
const { CAMPAIGN_PAGE } = Subs.ANALYTIC_EVENTS;
const { CAMPAIGN_PAGE_VIEW } = Subs.ANALYTIC_ACTIONS;
sendAnalyticEventSync(CAMPAIGN_PAGE, { action: CAMPAIGN_PAGE_VIEW });
getAnalyticEventHistory()
Returns the analytics event history from wherever it is currently being stored.
Input Validation
These are functions you can import and use for input validation with custom forms or any other subscription related uses.
emailValidation(email:String)
Returns true if the email name contains only:
- Uppercase (A-Z) and lowercase (a-z) English letters
- Digits (0-9)
- Characters ! # $ % & ' * + - / = ? ^ _ ` { | } ~
- Character . (period, dot or fullstop) provided that it is not the first or last character and it will not come one after the other.
Returns true if the domain of the email address contains only:
- Uppercase (A-Z) and lowercase (a-z) English letters
- Digits (0-9)
- Character . (period, dot or fullstop)
nameValidation(name:String)
Returns true if the name contains only:
- Any characters except: '<>+_!@#$%^&*?.,' and numbers
- No double spaces or dashes
- Between 1 and 50 characters long
usDOBValidation(dob:String)
Returns true if DOB date format:
- Matches the mm/dd/yyyy pattern
- The date is before today (current date)
euDOBValidation(dob:String)
Returns true if the DOB date format:
- Matches the dd/mm/yyyy pattern
- The date is before today (current date)
addressValidation(address:String, required:Boolean = false)
Returns true if the address is required (defaults to false) and the address contains only:
- Any characters except: "<>+_!@$%^&*?"
- Between 1 and 256 characters long
cityValidation(city:String, required:Boolean = false)
Returns true if the city is required (defaults to false) and the city contains only:
- Any characters except: "<>+_!@$%^&*?" and numbers
- Between 1 and 100 characters long
stateValidation(state:String, required:Boolean = false)
Returns true if the state is required (defaults to false) and the state contains only:
- Any characters except: "<>+_!#@$%^&*?" and numbers
- Between 1 and 100 characters long
postalCodeValidation(code:String, required:Boolean = false)
Returns true if the postal code is required (defaults to false) and the postalcode contains only:
- Any characters except: "<>+_!#@$%^&*?" and numbers
- Between 1 and 100 characters long
displayNameValidation(displayName:String)
Returns true if the display name contains only:
- Any characters
- Between 1 and 100 characters long
phoneNumberValidation(phoneNumber:String)
Returns true if the phone number contains only numbers and dashes
Utilities
These are functions you can import and use for form validation callbacks or any other subscription utilities you might have a use for.
valueRequired(value:String|Object|Number)
Checks to see if the value is null or an empty string. Returns false if value is missing or empty object, otherwise returns true.
getHash()
Returns the hash tag from the browser window path and specifically ignores the window object for server side rendering. Useful for deep linkning in SPA applications.
isLoggedIn()
Checks whether or not someone is logged in. Returns the object from the cookie or local storage or false if not logged in.
sortBy(dataArray:Array, sortField:String|Number, ascending, fieldDataType:Array)
Sorts an array of objects by a specified field and then returns the sorted array of objects.
valuesMatch(value1:String|Object|Number, value2:String|Object|Number)
Checks to see if two values are the same type and the same content. Returns false if the values are different types or the content doesn't match.
randomID(min:Number = 100, max:Number = 9999)
Returns a random number from min to max, defaults to 100 - 9999.
defaultResponseText(messageID:String|Number)
Returns an array with all localized text and error messages if no messageID is given, otherwise returns the string or object for the given messageID object key.
newScript(scriptId:String, srciptSrc:String, resolveCallBack:Function, rejectCallback:Function)
Returns a promise after loading the async script by resolving the resolveCallback or rejecting with the rejectCallback. This is useful when you need to load an SDK script if you aren't using the NPM package for the retail or identity or sales SDK.
fullAddressValidation(address:{firstAddress, secondAddress, city, state, country, postalCode})
Provides default full address validation by matching the SDK requirements. Returns true if all the fields (except secondAddress) are populated OR all fields are empty, returns false otherwise.
isHTMLObject(string:String)
HTML object string validator, returns true if the string contains any HTML tag, false otherwise.
isoCodesValidation(list)
This hecks if the ISO values from the custom country array matches the A2-ISO. Returns false if at least one of the ISO values is not present in the countryAbbreviations array (A2 International Organization for Standardization).
countryAbbreviations:Array
This is an array of country code abbreviations.
defaultCountryList:Array
This is an array of default country codes to display in a country code dropdown. It includes the ISO code and the name of the country.
Localization
Localization is a single object that you can pass into the SPAs and some components in order to modify the text or error codes that are displayed to a user. This is especially useful if you need to display subscriptions in multiple languages. This object contains keys for display text and for error codes and setting custom country codes and regions.
Display Text
Property | Type | Description |
---|---|---|
signUp | String | The sign up header |
signUpButton | String | The sign up button |
signIn | String | The sign in header |
signInButton | String | The sign in button |
String | The email address input field label | |
emailPlaceholder | String | The placeholder for the email input address field |
password | String | The label for the password input field |
passwordPlaceholder | String | The placeholder for the password input field |
forgotPasswordLink | String | The text for the forgot password link |
rememberMeCheckbox | String | The text next to the remember me checkbox |
secondLastName | String | The label for the second last name field |
secondLastNamePlaceholder | String | The placeholder for the second last name field |
loading | String, JSX Element | The message or element displayed when something is loading |
profile | String | The profile page header |
firstName | String | The label for the first name input field |
lastName | String | The label for the last name input field |
displayName | String | The label for the display name input field |
dob | String | The label for the date of birth input field |
gender | String | The label for the gender radio buttons |
female | String | The text for the female gender radio button |
male | String | The text for the male gender radio button |
nonConforming | String | The text for the non conforming gender radio button |
preferNotToSay | String | The text for the perfer not to say gender radio button |
statusBarIdentity | Object | Object containing props used to configure the status bar for the IdentitySPA |
statusBarIdentity.statusBarItems | Object | Object containing an property for each status bar object (object property). Each object property contains a display (string) property as well as an optional link property (to make it clickable) |
statusBarRetail | Object | Object containing props used to configure the status bar for the RetailSPA |
statusBarRetail.statusBarItems | Object | Object containing an property for each status bar object (object property). Each object property contains a display (string) property as well as an optional link property (to make it clickable) |
manageSubsPageTitle | String, JSX Element | Manage Subs Page - Title |
manageSubStatusLabel | String, JSX Element | Manage Sub - Status Label |
manageSubStatusInputPlaceholder | String | Manage Sub - Status Input Placeholder |
manageSubStatusRenderInputContent | Function | Manage Sub - Status Render Input Content |
manageSubActionLabel | String, JSX Element | Manage Sub - Action Label |
manageSubActionInputPlaceholder | String | Manage Sub - Action Input Placeholder |
manageSubActionCancelReasons | Array | Manage Sub - Action Cancel Reason Options List |
manageSubActionBarCancelSubscriptionButtonContent | String, JSX Element | Manage Sub - Action Bar Cancel Subscription Button Content |
manageSubActionBarSubmitButtonContent | String, JSX Element | Manage Sub - Action Bar Submit Button Content |
manageSubActionBarCancelButtonContent | String, JSX Element | Manage Sub - Action Bar Cancel Button Content |
manageSubActionBarRenewSubscriptionButtonContent | String, JSX Element | Manage Sub - Action Bar Renew Subscription Button Content |
manageSubActionBarRenewSubscriptionRenderLabelContent | String, JSX Element | Manage Sub - Action Bar Renew Subscription Render Label Content |
manageSubActionBarShowSubscriptionsButtonContent | String, JSX Element | Manage Sub - Action Bar Show Subscriptions Button Content |
manageSubActionBarShowSubscriptionsLabelContent | String, JSX Element | Manage Sub - Action Bar Show Subscriptions Label Content |
manageSubActionAlertSuccessContent | String, JSX Element | Manage Sub - Action Alert Success Content |
manageSubActionAlertErrorContent | String, JSX Element | Manage Sub - Action Alert Error Content |
manageSubActionAlertDuration | Number | Manage Sub - Action Alert Duration |
manageSubLoadingIndicator | String, JSX Element | Manage Sub - Loading Indicator |
manageSubRenewSubscriptionCampaignID | String, Number | Manage Sub - "Renew Subscription" CampaignID |
manageSubShowSubscriptionsCampaignID | String, Number | Manage Sub - "Show Subscription" CampaignID |
manageSubRenewSubscriptionURL | String | Manage Sub - Renew Subscription URL |
manageSubShowSubscriptionOptionsURL | String | Manage Sub - Show Subscription Options URL |
orderHistoryTableTitle | String, JSX Element | Order History Table - Title to use on the table |
orderHistoryTableDisplayConfig | Function | Order History Table - Function that returns a configuration object used for providing table display parameters to child Table component |
address1 | String | Label for the first address line input field |
address2 | String | Label for the second address line input field |
city | String | Label for the city address input field |
state | String | Label for the state/region address input field |
country | String | Label for the country dropdown field |
postalCode | String | Label for the postal code input field |
saveChanges | String | Text for save changes buttons |
order | String | The order header |
remove | String | The remove item from cart button text |
quantity | String | The quantity label on the order cart summary |
tax | String | The tax label on the order cart summary |
subtotal | String | The subtotal label on the order cart summary |
total | String | The total label on the order cart summary |
checkout | String | The text on the checkout button |
SDKFailure | String | Message to display to users when the SDK does not load |
userProfileFailure | String | Message to display to users when their profile doesn't load |
profileUpdateSuccessText | String | Message to display to users when their profile updates successfully |
toggle | String | Alternative 503 compliance text for tooggling a checkbox value |
termsCheckbox | String | Text label to display beside the checkbox for accepting terms and conditions |
termsAndConditions | String | Text to display that shows the terms, privacy and GDPR policies. Includes special keywords that can be added to customize the text: {{termsUrl}}, {{termsLabel}}, {{privacyUrl}}, {{privacyLabel}}, {{GDPRUrl}}, {{GDPRLabel}} |
termsLink | String | Text to be substituted into the {{termsLink}} keyword in the termsAndConditions text |
privacyLink | String | Text to be substituted into the {{privacyLink}} keyword in the termsAndConditions text |
GDPRLink | String | Text to be substituted into the {{GDPRLink}} keyword in the termsAndConditions text |
productCardGetOfferButtonText | String | Text on the button of a product card |
productPriceRadioButtonsLabel | String | Text on the product price radio button label |
confirmationPageHeaderText | String | Text that is shown on the payment confirmation form |
confirmationPageSubHeaderText | String | Sub-text that is shown on the payment confirmation form |
confirmationPageRedirectLinkText | String | Text that appears on the redirect link on the confirmation page |
createOrderPhoneNumberLabel | String | Label that appears on the phone number input field |
paymentOptions | String | Label for payment processor radio buttons |
paywallModalHeaderText | String | Paywall modal header text |
paywallModalSubheaderText | String | Paywall modal sub-header text |
paywallModalDescriptionText | String | Description text on the paywall modal |
paywallModalOfferText | String | Text shown for the paywall offer to view a campaign |
paywallModalAllOffersText | String | Text to view all offers in a campaign |
paywallModalSignInText | String | Text to sign in from the paywall modal |
paywallModalSignInMessageText | String | Text to sign in if you already have an account |
emailVerifiedSuccess | String | Text to show once an email has been verified |
emailVerificationInProgress | String | Text to show while trying to verify the email address |
signInRedirectToRegisterLinkText | String | Text to redirect to create a new account |
registerRedirectToSignInLinkText | String | Text to redirect to sign in to an existing account |
countryList | Array | An array of objects containing the ISO and name for each country ie. [{ ISO: "undefined", name: "N/A" }] |
Error Codes
Property | Description |
---|---|
0009c | Missing org headers |
0014a | Access denied |
0014b | Unexpected server error |
00016c | Product does not exist |
00017c | Pricing strategy not found |
00017d | Pricing rate not found |
100005 | Max batch size is 100 |
100011 | Access denied |
100012 | Only refresh token can be used to extend session |
100014 | Account is locked |
100015 | Account is disabled |
100018 | Updates can only be made within 60 minutes of signing in |
100022 | Failed to upload image |
100023 | Display name already in use |
100050 | Address line 1 is required |
100052 | Address line 2 must be between 1 and 256 characters |
100053 | Locality is required |
100090 | First name must be between 1 and 50 characters |
100096 | Invalid email |
100101 | Nonce is required |
100103 | New password does not meet strength requirements |
100130 | Missing start date |
100138 | Report in S3 not found |
100200 | Old password does not meet strength requirements |
100203 | New password does not meet strength requirements |
110010 | Invalid username or password |
130001 | ReCaptcha token invalid |
130051 | Email address is not verified |
200061 | Offer not found |
200065 | Campaign not found |
200066 | Offer not found |
200101 | Campaign not found |
200710 | No more rates available |
300001 | Missing items |
300002 | Empty items |
300003 | SKU is missing |
300004 | SKU is empty |
300005 | Invalid character(s) in SKU |
300006 | Invalid number of characters in SKU |
300007 | Missing quantity |
300008 | SKU not found in cart |
300009 | Invalid email |
300010 | Invalid character in phone number, allowed characters include 0-9 and - |
300011 | Token is empty |
300012 | Cart not found |
300013 | Cart is empty |
300014 | Payment provider not found |
300015 | Order not found |
300016 | Unexpected server error |
300017 | Unable to retrieve response from Payment Express, contact tech support |
300018 | Subscription not found |
300019 | Access denied |
300020 | Profile not found |
300022 | Failed to delete image |
300030 | Not found |
300031 | Username not available |
300033 | Nonce not found or expired |
300036 | New password does not meet strength requirements |
300037 | Password must be reset |
300039 | Duplicate identity type |
300040 | Invalid username or password |
300041 | Email domain is blacklisted |
300044 | At least one identity needs to remain on the user |
300050 | Email already verified |
300051 | Address line 1 must be between 1 and 256 characters |
300052 | Email address cannot be empty |
300053 | Email verification nonce required |
300054 | Locality must be between 1 and 100 characters |
300055 | Region must be between 1 and 100 characters |
300056 | Postal code must be between 1 and 100 characters |
300057 | Timed out while talking to Payment Express |
300058 | Address type is required |
300059 | Subscription not in a state that can be canceled |
300060 | Attribute name is required |
300061 | Attribute name must be between 1 and 30 characters |
300062 | Attribute value is required |
300063 | Attribute value must be between 1 and 1000 characters |
300064 | Attribute type is required |
300070 | Phone number is required |
300071 | Phone number must be between 10 and 12 characters |
300072 | Contact type is required |
300073 | Parent subscription has been shared with max number of associates |
300075 | Invalid email address format |
300077 | Missing email address |
300078 | Empty email address |
300079 | Invalid SKU |
300080 | Username is required |
300081 | Username must be between 5 and 100 characters long |
300082 | Password is required |
300083 | Password does not meet strength requirements |
300085 | Duplicate request to Payment Express |
300090 | Configuration not found |
300091 | Last name must be between 1 and 50 characters |
300092 | Display name is required |
300093 | Display name must be between 1 and 100 characters |
300094 | Email must be between 1 and 100 characters |
300095 | Email is required |
300096 | Address line 1 must be between 1 and 256 characters |
300097 | Address line 2 must be between 1 and 256 characters |
300098 | Locality must be between 1 and 100 characters |
300099 | Region must be between 1 and 100 characters |
300100 | Country must be 2 characters |
3001001 | User not found |
3001002 | User not allowed to activate account |
300101 | Maximum of 100 characters in address postal code |
300102 | New password is required |
300105 | Picture must be between 1 and 255 characters |
300106 | Invalid date of birth format |
300107 | legacy ID must be between 1 and 50 characters |
300112 | Token is missing |
300113 | Invalid character in token |
300114 | Invalid token length |
300117 | Billing address is required |
300118 | Address type is required |
300123 | Missing payment provider token |
300124 | payment provider token may not be empty |
300125 | Missing redeem code |
300126 | Empty redeem code |
300127 | Invalid character in first name |
300128 | First name must be between 1 and 100 characters |
300129 | Invalid character in last name |
300130 | Last name must be between 1 and 100 characters |
300131 | Missing end date |
300133 | Missing report type |
300136 | Report not found |
300137 | Missing price code |
300138 | Empty price code |
300139 | Invalid price code |
300140 | Invalid number of characters in price code |
300141 | Too many character in campaign code |
300142 | Invalid character(s) in campaign code |
300151 | Missing client ID |
300160 | Problem communicating with Spreedly |
300161 | Unable to initialize session with Spreedly |
300162 | Timed out while talking to Spreedly |
300163 | Unable to retrieve response from Spreedly, contact tech support |
300164 | Spreedly declined the transaction |
300165 | Invalid address line 1 |
300167 | Invalid address locality |
300168 | Invalid address region |
300169 | Invalid address country |
300171 | Invalid character in second last name |
300172 | Second last name must be between 1 and 50 characters |
300178 | Unexpected error communicating with PayPal |
300180 | Invalid payment method expiration length |
300181 | PayPal declined the transaction |
300199 | Group email domain Not Found |
300200 | Old password is required |
300166 | Address 2 is invalid |
300023 | DisplayName already in use |
300201 | invalid character in reason or too many (2048) |
300202 | New Password is required |
300203 | New Password does not meet strength requirements |
300204 | Invalid size |
300205 | Invalid format |
300300 | Username is required |
300301 | Username must be between 5 and 100 characters long |
3003j | Country must be 2 characters |
300400 | Identity is required |
300401 | Profile is required |
300500 | User status is not provided |
3007010 | Max number of contacts is 100 |
3007011 | Max number of addresses is 100 |
3007012 | Max number of attributes is 100 |
330011 | Invalid number of characters in phone number, use between 0 and 12 characters |
330056 | Unable to initialize session with Payment Express |
330059 | Parent subscription no longer active |
330060 | Subscription already rescued |
330061 | Calling user not allowed to cancel subscription |
330062 | Calling user not allowed to rescue subscription |
330072 | Requestor’s tenant does not match that of parent subscription |
330081 | SKU not found |
330090 | Invalid address type |
330130 | Missing startDate |
330138 | Report in S3 not found |
330139 | Invalid price code |
330165 | SlimPay declined transaction |
330166 | Transaction was not processed by SlimPay |
330167 | Transaction canceled by user |
330180 | Customer declined PayPal billing agreement |
330201 | Member is already in Group |
requiredField | Field is required |
passwordsDoNotMatch | Passwords do not match |
dobRequired | Please enter your Date of Birth |
googleSdkError | Google SDK failed to load |
googleSignOnError | Google Sign In failed |
facebookSdkError | Facebook SDK failed to load |
facebookSignOnError | Facebook Sign In failed |
userNotOfAge | You must be over 14 years old |
Country Codes
This is a property countryList
in the localization object that takes an object with the mapping of all the ISO country codes and regions you would like to be available in your forms. By default uses the following format:
[
{
ISO: "undefined",
name: "N/A",
regions: [
"N/A",
],
},
]
Styles
Class Name | Description |
---|---|
wrapperClasses | Wrap individual forms and components within the SPA |
headerClasses | Form and component headers |
errorClasses | Apply to error messages |
errorHeadlineSize | H# size to use for error messages |
successClasses | Apply to successful messages |
labelClasses | Apply to input field labels |
buttonClasses | Apply to buttons and submit input fields |
inputClasses | Apply to input types of text and password |
checkboxClasses | Apply to checkbox input types |
dropdownClasses | Apply to select dropdowns |
feedbackClasses | Apply to feedback messages tied directly to an input field for checking if required or has proper validation |
radioWrapperClasses | Apply to the wrapper around all radio inputs in a series |
radioContainerClasses | Wraps each individual radio label and input field |
radioButtonClasses | Apply to a radio input field |
radioLabelClasses | Apply to the label for each radio button |
addressWrapperClasses | Wraps around all of the address fields |
headlineImageWrapperClasses | Applies to the wrapper around the campaign header image |
headlineImageWrapperStyles | Apples inline styles to the header image |
headlineImageSmBrkPnt | The breakpoint for the small image size on the campaign header image in pixels |
headlineImageMdBrkPnt | The breakpoint for medium image sizes on the campaign header image in pixels |
headlineImagePageTitleSize | The H# size of the headline that overlays on top of the campaign header image |
headlineImageTitleClasses | Classes applied to the headline that overlays on top of the campaign header image |
headlineImagePageSubTitleSize | The H# size of the sub-headline that overlays on top of the campaign header image |
headlineImageSubTitleClasses | Classes applied to the sub-headline that overlays on top of the campaign header image |
productCardsContainerWrapperClasses | Wraps all of the product cards in a campaign |
productCardWrapperClasses | Applies to the container around a product card in a campaign |
productCardHeaderClasses | Applies to a header in a product card |
productCardHeaderSize | The H# size of the header in a product card |
productCardUnorderedListWrapperClasses | Classes applied around all the items in an unordered list on a campaign product card |
productCardUnorderedListItemClasses | Classes applied to an idividual item in an unordered list on a campaign product card |
productCardGetOfferButtonClasses | Classes applied to the get offer button on a campaign product card |
productCardLazyLoadingImageWrapperClasses | Classes applied to the wrapper around lazy loaded images on a campaign product card |
productCardLazyLoadingImageClasses | Classes applied to the lazy loaded image on a campaign product card |
productCardLazyLoadingImageLoaderClasses | Classes applied to the wrapper around image loader on a campaign product card |
productPriceRadioButtonsWrapperClasses | Apply to the wrapper around all radio price buttons on a campaign product card |
productPriceRadioButtonsLabelClasses | Apply to the label on a radio price button on a campaign product card |
productPriceRadioButtonsRadioButtonClasses | Apply to the price radio button on a campaign product card |
productPriceRadioButtonsRadioLabelClasses | Apply to the label on a price radio button on a campaign product card |
productRadioContainerClasses | Wraps a label and price radio button on a campaign product card |
singleProductPriceFieldHeadlineSize | The H# size for a product price headline on a campaign product card |
singleProductPriceFieldHeadlineClasses | Apply to the product price headline on a campaign product card |
disclaimerMessageHeadlineSize | The H# size of the header for the disclaimer below a campaign product card |
disclaimerMessageClasses | Apply to the disclaimer below a campaing product card |
statusBarWrapperClasses | Wraps the items in a status bar |
statusBarItemClasses | Applies to each item in a status bar |
statusBarDefaultClasses | Applies to the un-selected items in a status bar |
statusBarHighlightClasses | Applies to the selected item in a status bar |
statusBarItemSize | The H# size of the text on a status bar item |
confirmationPageWrapperClasses | Wraps the confirmation page contents |
confirmationPageHeaderClasses | Apply to the headline on the confirmation form |
confirmationPageHeaderSize | The H# size of the header text on the confirmation form |
confirmationPageSubHeaderClasses | Apply to the sub-headline on the confirmation form |
confirmationPageSubHeaderSize | The H# size of the sub-header text on the confirmation form |
confirmationPageRedirectLinkClasses | Apply to the redirect link on the confirmation form |
createOrderInfoWrapperClasses | Wraps the order information on the checkout form |
cartWrapperClasses | Wraps the cart information on the checkout form |
cartItemClasses | Apply to an item in the cart on the checkout form |
orderWrapperClasses | Wraps the order item details on a checkout form |
cartSummaryClasses | Wraps the summary section on the checkout form |
manageSubsPageClassName | Classes added to "Manage Subs Page" |
manageSubsPageManageSectionClassName | Classes added to "Manage Subs Page - Manage Section" |
manageSubsPageHistorySectionClassName | Classes added to "Manage Subs Page - History Section" |
manageSubsPageTitleClassName | Classes added to "Manage Subs Page - Title" |
manageSubContainerClassName | Classes added to "Manage Sub - Container" |
manageSubStatusContainerClassName | Classes added to "Manage Sub - Status Container" |
manageSubStatusLabelClassName | Classes added to "Manage Sub - Status Label" |
manageSubStatusCancelInitializedLabelClassName | Classes added to "Manage Sub - Status Cancel Initialized Label" |
manageSubStatusInputWrapperClassName | Classes added to "Manage Sub - Status Input Wrapper" |
manageSubStatusCancelInitializedInputWrapperClassName | Classes added to "Manage Sub - Status Cancel Initialized Input Wrapper" |
manageSubStatusInputClassName | Classes added to "Manage Sub - Status Input" |
manageSubStatusCancelInitializedInputClassName | Classes added to "Manage Sub - Status Cancel Initialized Input" |
manageSubActionContainerClassName | Classes added to "Manage Sub - Action Container" |
manageSubActionLabelClassName | Classes added to "Manage Sub - Action Label" |
manageSubActionInputWrapperClassName | Classes added to "Manage Sub - Action Input Wrapper" |
manageSubActionDropdownClassName | Classes added to "Manage Sub - Action Dropdown" |
manageSubActionDropdownStyle | Styles added to "Manage Sub - Action Dropdown" |
manageSubActionBarClassName | Classes added to "Manage Sub - Action Bar" |
manageSubActionBarNoneClassName | Classes added to "Manage Sub - Action Bar ('No Subscriptions' state)" |
manageSubActionBarCancelClassName | Classes added to "Manage Sub - Action Bar ('Active Subscription' state)" |
manageSubActionBarRenewClassName | Classes added to "Manage Sub - Action Bar ('Expired Subscription' state)" |
manageSubActionBarCancelSubscriptionButtonClassName | Classes added to "Manage Sub - Action Bar Cancel Subscription Button" |
manageSubActionBarCancelSubscriptionButtonStyle | Styles added to "Manage Sub - Action Bar Cancel Subscription Button" |
manageSubActionBarSubmitButtonClassName | Classes added to "Manage Sub - Action Bar Submit Button" |
manageSubActionBarSubmitButtonStyle | Styles added to "Manage Sub - Action Bar Submit Button" |
manageSubActionBarCancelButtonClassName | Classes added to "Manage Sub - Action Bar Cancel Button" |
manageSubActionBarCancelButtonStyle | Styles added to "Manage Sub - Action Bar Cancel Button" |
manageSubActionBarRenewSubscriptionButtonClassName | Classes added to "Manage Sub - Action Bar Renew Subscription Button" |
manageSubActionBarRenewSubscriptionButtonStyle | Styles added to "Manage Sub - Action Bar Renew Subscription Button" |
manageSubActionBarRenewSubscriptionLabelClassName | Classes added to "Manage Sub - Action Bar Renew Subscription Label" |
manageSubActionBarShowSubscriptionsButtonClassName | Classes added to "Manage Sub - Action Bar Show Subscriptions Button" |
manageSubActionBarShowSubscriptionsButtonStyle | Styles added to "Manage Sub - Action Bar Show Subscriptions Button" |
manageSubActionBarShowSubscriptionsLabelClassName | Classes added to "Manage Sub - Action Bar Show Subscriptions Label" |
manageSubActionAlertSuccessClassName | Classes added to "Manage Sub - Alert Success" |
manageSubActionAlertErrorClassName | Classes added to "Manage Sub - Alert Error" |
orderHistoryTableContainerClassName | Classes added to "Order History Table - Container" |
orderHistoryTableTableClassName | Classes added to "Order History Table - Table" |
orderHistoryTableTitleClassName | Classes added to "Order History Table - Title" |
orderHistoryTableHeadingRowClassName | Classes added to "Order History Table - Heading Row" |
orderHistoryTableHeadingColClassName | Classes added to "Order History Table - Heading Column" |
orderHistoryTableHeadingColSortButtonClassName | Classes added to "Order History Table - Heading Column Sort Button" |
orderHistoryTableHeadingColSortButtonIconClassName | Classes added to "Order History Table - Heading Column Sort Button Icon" |
orderHistoryTableHeadingColSortButtonIconAscending | Rendering (icon) to use for "Order History Table - Heading Column Sort Button Icon Ascending" |
orderHistoryTableHeadingColSortButtonIconDescending | Rendering (icon) to use for "Order History Table - Heading Column Sort Button Icon Descending" |
orderHistoryTableRowClassName | Classes added to "Order History Table - Row" |
orderHistoryTableRowHoverClasses | Classes added to "Order History Table - Row Hover" |
orderHistoryTableRowExpandedClasses | Classes added to "Order History Table - Row Expanded" |
orderHistoryTableRowCollapsedClasses | Classes added to "Order History Table - Row Collapsed" |
orderHistoryTableRowExpandedPanelClasses | Classes added to "Order History Table - Row Expanded Panel" |
orderHistoryTableRowDataClassName | Classes added to "Order History Table - Column" |
orderHistoryTableRowToggleButtonColClassName | Classes added to "Order History Table - Toggle Button Column" |
orderHistoryTableRowToggleButtonColStyle | Styles added to "Order History Table - Toggle Button Column" |
orderHistoryTableRowToggleButtonClassName | Classes added to "Order History Table - Toggle Button" |
orderHistoryTableRowToggleButtonStyle | Styles added to "Order History Table - Toggle Button" |
orderHistoryTableRowToggleButtonExpandIcon | Rendering to use for "Order History Table - Toggle Button Expand Icon" |
orderHistoryTableRowToggleButtonCollapseIcon | Rendering to use for "Order History Table - Toggle Button Collapse Icon" |
orderHistoryTableRowExpandablePanelClassName | Classes added to "Order History Table - Row Expandable Panel" |
orderHistoryTableRowExpandablePanelItemClassName | Classes added to "Order History Table - Row Expandable Panel Item" |
orderHistoryTableRowExpandablePanelItemHeadingClassName | Classes added to "Order History Table - Row Expandable Panel Item Heading" |
orderHistoryTableRowExpandablePanelItemDataClassName | Classes added to "Order History Table - Row Expandable Panel Item Body" |
import Subscriptions from '@arc-core-components/feature_subscriptions';
<Subscriptions.IdentitySPA
debug={false}
config={{
useCookies: true,
autoLogin: true,
secondLastName: false,
recaptcha: {
enabled: true,
token: "your_site_key_here",
position: "above",
size: "invisible",
},
termsUrl: "http://my.site.com/terms",
privacyUrl: "http://my.site.com/privacy",
GDPRUrl: "http://my.site.com/gdpr",
}}
styles={{
wrapperClasses: 'row col m-2',
errorClasses: 'row text-danger',
errorHeadlineSize: 4,
successClasses: 'row text-success',
buttonClasses: 'btn btn-primary w-100',
}}
/>
Custom Forms
There will be times when one of the forms provided in the SPA does not meet business requirements or you need a custom solution. Here are some examples on how you can create a custom form using the existing form elements provided in core components. One thing to note with custom forms is that, depending on the use of the form, you may or may not be able to use it with the out of the box SPA provided in core components. Sometimes creating a custom form will also require that you create a custom spa.
Example
This creates a sample custom login form (username, password, remember me, lost password link, recaptcha) with analytics and custom fields that will allow you to control the form title, successful login url and whether or not to use cookies.
import React, { Component } from "react";
import PropTypes from "prop-types";
import Subscriptions from '@arc-core-components/feature_subscriptions';
const { LOGIN } = Subscriptions.ANALYTIC_EVENTS;
const { LOGIN_ATTEMPT, LOGIN_SUCCESS, LOGIN_FAILED } = Subscriptions.ANALYTIC_ACTIONS;
const { LOCAL } = Subscriptions.ANALYTIC_ENVIRONMENT;
/**
* @class Login
* @desc Creates a custom login form
*
* @return {Object} <Login /> React component
*/
export default class Login extends Component {
/**
* Default constructor
* @param {Object} props - properties passed to the component
*
* @return null
*/
constructor(props) {
super(props);
this.state = {
email: null,
password: null,
error: null,
rememberMe: true,
disabled: false,
};
}
/**
* Set the state of the remember me option
*
* @param {Boolean} toggle - true|false to remember me
* @return null, sets internal state
*/
rememberMeCallback = (toggle) => {
this.setState({ rememberMe: toggle });
};
/**
* Callback for validating email addresses on this form
*
* @param {String} email - the email address to validate
* @return {Boolean} the state of the validation
*/
emailCallback = (email) => {
if (emailValidation(email)) {
this.setState({ email });
return true;
}
this.setState({ email: null });
return false;
};
/**
* Checks to see if the email address has been entered or not
*
* @param {String} email - the email address to validate
* @return {Boolean} the state of the validation
*/
emailRequiredCallback = (email) => {
if (!email) {
this.setState({ error: "email required" });
return true;
}
this.setState({ error: "" });
return false;
};
/**
* Callback to see if the password is valid or not
*
* @param {String} password - the password to validate
* @return {Boolean} the state of the validation
*/
passwordCallback = (password) => {
if (password) {
this.setState({ password });
return true;
}
this.setState({ password: null });
return false;
};
/**
* Checks to see if the password has been entered or not
*
* @param {String} email - the email address to validate
* @return {Boolean} the state of the validation
*/
passwordRequiredCallback = (password) => {
if (!password) {
this.setState({ error: "password required" });
return true;
}
this.setState({ error: "" });
return false;
};
/**
* Callback to see if the login form can be submitted or not
*
* @return {Object} status object
*/
loginCallback = () => {
const { email, password, rememberMe, error } = this.state;
// use these settings from PB admin configuration
const { useCookies, loginSuccessUrl } = this.props.customFields;
if (error || !email || !password) {
Subscriptions.sendAnalyticEventSync(LOGIN, { action: LOGIN_FAILED, environment: LOCAL });
return {
status: false,
error,
};
}
// disable the submit button
this.setState({ disabled: true });
// attempt to login
Subscriptions.Identity("login", email, password, {
rememberMe: rememberMe,
cookie: useCookies,
recaptchaToken: "YOUR_TOKEN_HERE",
})
.then(() => Subscriptions.sendAnalyticEventSync(LOGIN, { action: LOGIN_SUCCESS }, () => {
// login successful, update the state of the form
this.setState({ error: null });
// forward them to an authenticated route
window.location = loginSuccessUrl;
}))
.catch(result => Subscriptions.sendAnalyticEventSync(LOGIN, { action: LOGIN_FAILED, code: result.code }, () => {
const errorCode = result.code.replace(/[\W_]+/g, "");
// login failed, set the state to match the login error coming back and enable the login button again
this.setState({ error: result.message, disabled: false });
return {
status: false,
...result,
};
}));
// enable the sign in button
return {
disabled: false,
status: false,
};
};
/**
* Render the login form
*
* @return {Object} sign in form
*/
render() {
const { disabled, rememberMe } = this.state;
// get the title of the form from the PB admin fields
const { formTitle } = this.props.customFields;
return (
<div className="wrapperClass">
<Subscriptions.Header className="headerClass">{formTitle}</Header>
<div className="error">{this.state.error}</div>
<Subscriptions.EmailInput
callback={this.emailCallback}
requiredCallback={this.emailRequiredCallback}
/>
<Subscriptions.PasswordInput
callback={this.passwordCallback}
requiredCallback={this.passwordRequiredCallback}
/>
<Subscriptions.ForgotPasswordLink />
<Subscriptions.SignInButton
disabed={disabled}
callback={this.loginCallback}
/>
<Subscriptions.RememberMeCheckbox defaultChecked={rememberMe} />
</div>
);
}
}
Login.propTypes = {
customFields: PropTypes.shape({
formTitle: PropTypes.string.tag({
defaultValue: 'Login',
name: 'Login Form Title',
group: 'Text',
}),
loginSuccessUrl: PropTypes.string.tag({
defaultValue: '/profile',
name: 'Login Success URL',
group: 'Settings',
}),
useCookies: PropTypes.bool.tag({
defaultValue: false,
name: 'Use Cookies?',
group: 'Settings',
}),
};
Login.defaultProps = {
customFields: {
formTitle: "Login",
loginSuccessUrl: "/profile",
useCookies: false,
},
};
Custom SPA
Sometimes you need to make customizations to the workflow provided in our Identity or Retail SPAs or you want to create your own SPA. Here is an example of how you can create a custom SPA using a mix of your own custom forms and forms provided for you in core components.
Example
import React, { Fragment } from "react";
import PropTypes from "prop-types";
import {
HashRouter, Switch, Route, Redirect,
} from "react-router-dom";
import Subscriptions from '@arc-core-components/feature_subscriptions';
import Profile from 'your-custom-profile-component';
import Login from 'your-custom-login-component';
/**
* @class CustomIdentitySPA
*/
export default class CustomIdentitySPA extends React.Component {
/**
* Default constructor
*/
constructor(props) {
super(props);
// figure out if user is logged in or not
const user = Subscriptions.isLoggedIn();
this.state = {
/**
* we recommend keeping the user'ss data in a global state
* or react context so you can pass it to any of the forms
* in your SPA without having to reload it each time
*/
identity: user || {},
/**
* You can create a custom function to update global state
* shared between all forms or use react context
*/
update: (key, value) => {
this.setState({ [key]: Object.assign(this.state[key], value) });
},
};
}
/**
* Renders the SPA using HashRoutes to navigate, using regular
* routes may conflict with PB Admin's routing configuration.
* You can add as many routes as you would like.
*/
render() {
return (
<HashRouter>
<Switch>
<Route
exact
path="/profile"
render={(props) => (Subscriptions.isLoggedIn()
? <Profile {...this.state} {...props} />
: <Redirect to="/login" />
)}
/>
<Route
exact
path="/sign-out"
render={() => <Subscriptions.SignOutFormSPA {...this.state} signOutUrl="/login" />}
/>
<Route
path="*"
render={(props) => <Login {...this.state} {...props} />}
/>
</Switch>
</HashRouter>
);
}
}
IdentitySPA.propTypes = {};