Vue Storefront is now Alokai! Learn More
Register

SAP Commerce Cloud: B2B Register

SAP B2B Registration module consists set of steps that an entity has to follow in order to access or obtain account credentials for purchasing in commerce.

Features

SAP B2B Registration module alters already available registration flow. In B2B process works differently, there is no possibility to set up password, but only send request for an account.

  • Modified registration form for B2B commerce.
  • Modal with success message once registration request is sent.

Installation

Add the module files

To install the module, you need an enterprise license and credentials. Contact your Customer Support Manager if you're already a customer. If you're not a customer yet, contact our sales team.

From the root of your project run the following command:

npx @vsf-enterprise/storefront-cli add-module register-b2b -e sapcc-b2b

Follow the instructions in the command line to complete the installation. To make sure the installation is finished, go to the apps/storefront-middleware/sf-modules folder and check if there's a folder named register-b2b inside.

Middleware Extension

This module modify one middleware method. Make sure to install extension in middleware to start using the Register-B2B module.

// storefront-middleware/integrations/sapcc/config.ts

import type { MiddlewareConfig } from "@vsf-enterprise/sapcc-api";
import type { ApiClientExtension, Integration } from "@vue-storefront/middleware";
import { multistoreExtension, unifiedApiExtension } from "./extensions";
import { b2bRegisterExtensionFactory } from "@sf-modules-middleware/register-b2b"; 
// ...

export const config = {
  location: "@vsf-enterprise/sapcc-api/server",
  configuration: {
    // ...
  },
  extensions: (extensions: ApiClientExtension[]) => [
    ...extensions,
    unifiedApiExtension,
    ...(IS_MULTISTORE_ENABLED === "true" ? [multistoreExtension] : []),
    b2bRegisterExtensionFactory(),   ],
} satisfies Integration<MiddlewareConfig>;

Then, export the type of the new extension in the types.ts file in the root directory of the Middleware.

// storefront-middleware/types.ts

export {
  type UnifiedEndpoints,
} from "./integrations/sapcc/types";

export type { B2BRegisterEndpoints } from "@sf-modules-middleware/register-b2b"; 

Frontend Implementation

1. Extend SDK configuration

First, you need to add the newly installed extension to the SDK config. To do so, edit the sdk/sdk.config.ts file in your Next.js Storefront directory.

// storefront-unified-nextjs/sdk/sdk.config.ts

import { contentfulModule } from '@vsf-enterprise/contentful-sdk';
import { CreateSdkOptions, createSdk } from '@vue-storefront/next';
import type { UnifiedEndpoints } from 'storefront-middleware/types'; import type {   UnifiedEndpoints,   B2BRegisterEndpoints, } from 'storefront-middleware/types'; 
//...

export const { getSdk } = createSdk(options, ({ buildModule, middlewareModule, middlewareUrl, getRequestHeaders }) => ({
  unified: buildModule(middlewareModule<UnifiedEndpoints>, {
    apiUrl: `${middlewareUrl}/commerce`,
    defaultRequestConfig: {
      headers: getRequestHeaders(),
    },
  }),
  b2bRegister: buildModule(middlewareModule<B2BRegisterEndpoints>, {     apiUrl: `${middlewareUrl}/commerce/b2b-register`,     defaultRequestConfig: {       headers: getRequestHeaders(),     },   }),   contentful: buildModule(contentfulModule, {
    apiUrl: `${middlewareUrl}/cntf`,
  }),
}));

export type Sdk = ReturnType<typeof getSdk>;

2. Modify register page form and add success modal

In your register.tsx page form has to be modified, field password and all checkbox have to be removed. Add message textarea form field with counter logic. Additionally SuccessModal has to be replaced with SuccessB2BRegisterModal.

// storefront-unified-nextjs/pages/register.tsx

import { FormEvent } from 'react'; import dynamic from 'next/dynamic'; import { SfButton, SfCheckbox, SfIconError, SfInput, SfLink, SfLoaderCircular } from '@storefront-ui/react'; import { type ChangeEvent, FormEvent, useState } from 'react'; import { SuccessB2BRegisterModal } from '@sf-modules/register-b2b'; import { SfButton, SfIconError, SfInput, SfLink, SfLoaderCircular, SfTextarea } from '@storefront-ui/react'; import { Trans, useTranslation } from 'next-i18next';
import { NextSeo } from 'next-seo';
import { Alert, FormHelperText, FormLabel, InputPassword, Link } from '~/components'; import { Alert, FormLabel, Link } from '~/components'; import { appRoutes } from '~/config';
...
import { AuthLayout } from '~/layouts';
import { SuccessB2BRegisterModal } from '@sf-modules/register-b2b'; 
const SuccessModal = dynamic(() => import('~/components/SuccessModal'), {   ssr: false, }); 
export const getServerSideProps = createGetServerSideProps({ i18nNamespaces: ['auth'] });

export default function RegisterPage() {
  const { t } = useTranslation('auth');
  const { mutate, isLoading, isSuccess, error } = useRegisterCustomer();
  const [messageValue, setMessageValue] = useState(''); 
  const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const customer = getFormData(event.target as HTMLFormElement);
    mutate(customer);
  };

  const characterLimit = 1000;   const charsCount = characterLimit - messageValue.length; 
  const onMessageChange = (event: ChangeEvent<HTMLTextAreaElement>) => {     const { value } = event.target;     setMessageValue(value);   }; 
  return (
    <>
      <NextSeo title={`${t('createAccount')} | Alokai Demo`} />
      <AuthLayout heading={t('createAccount')} data-testid="register-page">
        {isSuccess ? (
          <SuccessModal />           <SuccessB2BRegisterModal />         ) : (
          <>
            <div className="p-4 md:p-6 text-base mb-6 rounded-md bg-neutral-100 border border-neutral-200">
              ...
            </div>
            <form onSubmit={handleSubmit} className="md:border border-neutral-200 rounded-md px-0 md:p-6">
              ...
              <label className="block mb-4">
                <FormLabel>{t('email')}</FormLabel>
                <SfInput data-testid="email-input" name="email" type="email" size="lg" autoComplete="email" required />
              </label>
        
              <label className="block mb-6">
                <FormLabel>{t('password')}</FormLabel>
                <InputPassword
                  data-testid="password-input"
                  name="password"
                  size="lg"
                  autoComplete="current-password"
                  required
                  pattern="(?=.*\d)(?=.*[a-zA-Z]).{8,}"
                  title={t('passwordHint')}
               />
               <FormHelperText>{t('passwordHint')}</FormHelperText>
              </label>
              <label className="grid grid-cols-[24px_auto] gap-x-2 cursor-pointer mb-4">
                <SfCheckbox data-testid="terms-checkbox" className="m-[3px]" required name="terms" />
                <FormLabel className="!text-base !font-normal">
                  <Trans ns="auth" i18nKey="register.termsAndConditions">
                    * I declare that I have read and accept the&nbsp;
                    <SfLink as={Link} href={appRoutes.index.compile()} variant="primary">
                      Terms & Conditions
                    </SfLink>
                  </Trans>
                </FormLabel>
              </label>

              <label className="grid grid-cols-[24px_auto] gap-x-2 cursor-pointer mb-6">
                <SfCheckbox data-testid="newsletter-checkbox" className="m-[3px]" name="newsletter" />
                <FormLabel className="!text-base !font-normal">{t('register.newsletter')}</FormLabel>
              </label>

              <label>
                <span className="typography-text-sm font-medium">{t('message')}</span>
                <SfTextarea
                  className="w-full block min-h-[96px]"
                  value={messageValue}
                  onInput={onMessageChange}
                  maxLength={characterLimit}
                  placeholder={t('messagePlaceholder')}
                  name="message"
                />
                <p className="typography-hint-xs mt-0.5 mb-6 text-neutral-500 text-right">{charsCount}</p>
              </label>

              <p className="text-neutral-500 typography-text-sm mb-6">{t('markRequired')}</p>

              <SfButton>
                ...
              </SfButton>
            </form>
          </>
        )}
      </AuthLayout>
    </>
  );
}

Then we need to modify useRegisterCustomer so it would work with new registration flow for B2B.

// storefront-unified-nextjs/hooks/useCustomer/useRegisterCustomer.ts

import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query'; import type { B2BRegisterCustomerArgs } from '@sf-modules-middleware/sap-b2b'; import { isSdkRequestError } from '@vue-storefront/sdk';

...
export function useRegisterCustomer() {
  const queryClient = useQueryClient();   const sdk = useSdk();

   return useMutation(async (data: RegisterCustomerArgs) => sdk.unified.registerCustomer(data), {    return useMutation(async (data: B2BRegisterCustomerArgs) => sdk.b2bRegister.registerCustomer(data), {     onSuccess(data) {       queryClient.setQueryData(['customer'], data);       queryClient.invalidateQueries(['cart']);     },     retry: false,
    meta: {
      skipErrorNotification: isSdkRequestError,

Lastly only missing are translations for newly added textarea

// storefront-unified-nextjs/public/locales/en/auth.json

  ...
  "createAccount": "Create Account",   "createAccount": "Send Request",   "firstName": "First Name",
  "lastName": "Last Name",
  "email": "Email",
  "password": "Password",
  "message": "Message (optional)",   "messagePlaceholder": "Additional information regarding the intended account",   "register": {
    "toLogin": "Already have an account? Switch to <1>Log in</1>.",
  ...
// storefront-unified-nextjs/public/locales/de/auth.json

  ...
  "createAccount": "Benutzerkonto erstellen",   "createAccount": "Anfrage senden",   "firstName": "Vorname",
  "lastName": "Zuname",
  "email": "Email",
  "password": "Passwort",
  "message": "Nachricht (optional)",   "messagePlaceholder": "Zusätzliche Informationen zum beabsichtigten Konto",   "register": {
    "toLogin": "Sie haben bereits ein Konto? Wechseln Sie zu <1>Anmelden</1>.",
  ...

With these steps, your Register-b2b feature is now effectively integrated with SAP Commerce Cloud. You've just provided a practical solution for your customers to register into your Commerce!