Integrating using our SDK

As the CNS server will push the alerts and notifications to the wallet address and the DApp will need to integrate the compound React Component packages for showing the notifications to users, we need to provide an easy out-of-the-box React Component for DApp to integrate and save their time focusing on the DApp features. And we should give the information on the React Component's workflow.

Install Package

// npm
npm install @cronosid/react-bell

// yarn
yarn add @cronosid/react-bell

// pnpm
pnpm add @cronosid/react-bell

Integration

Parameters

To use the CNS notification service must need to connect the Wallet and Sign a signature to log in the CNS service. The user must sign a signature and set the header for the later API requests. If the user doesn't connect to a wallet and log in, you cannot do anything with CNS notifications, it is just a connect wallet tip.

So it will need to pass the

userAddress : identify the user and send notifications to this user

signMessage : the function to sign a message for CNS service and sign a message for subscribing or unsubscribing a channel

And there will be a env and chainId

env : Production or Staging

chainId : the number of the blockchain, a decimal number

Please know that the env is relative to the chainId. Eg. if the env is Production and the chainId is the MainNet chainId, if the env is Staging and the chainId is the TestNet chainId.

If you wanna the user bind the Telegram bot to receive the notifications, should pass tgInfo

tgInfo : it is an object variable

{
  botName: "your_tg_bot_name",
  cornerRadius: 8,
}

Note: If don't pass the tgInfo then it will don't have the tg bind flow in the SDK.

The botName is your tg bot name and the cornerRadius is the Telegram Login Widget button corner radius style.

And there is a isMobile param, which is the something customize desktop and mobile style param. true or false, it is an optional param, the default is false.

Optional and Mandatory Parameters

The mandatory parameters contain: userAddress, signMessage, env and chainId.

The optional parameters contain: tgInfo and isMobile.

Code Example

The demo code includes three component Notification, Entry and Modal.

The Notification component

import { NotifiContext, SignMethod } from "@cronosid/react-bell";

import { currentWallet } from "wallet";

import { Entry, Modal } from ".";

export const Notification = () => {
  const provider = currentWallet.useProvider(); // your provider
  const account = currentWallet.useAccount(); // your account

  return (
    <NotifiContext
      channelId="0xa2c4605bff800d59e680da598c53ee8a4ce02f66495932608478f6dd63c44a70"
      env="Staging"
      chainId={338}
      userAddress={account ?? ""}
      signMessage={async (message: string, signMethod: SignMethod) => {
        const signer = provider?.getSigner();
        const signerAddress = await signer?.getAddress();
        const params = [signerAddress, message];
        const signature: string = await provider?.send(signMethod, params);
        return signature;
      }}
      // tgInfo={{
      //   botName: "your_tg_bot_name",
      //   cornerRadius: 20,
      // }}
      // isMobile={false}
    >
      <Entry />
      <Modal />
    </NotifiContext>
  );
};

The Entry component

import { BellButton } from "@cronosid/react-bell";

export const Entry = () => {
  return <BellButton />;
};

The Modal component

import {
  useNotifiContext,
  NotificationContainer,
  Header,
  CloseButton,
  NotificationContent,
  ErrorTipContent,
  ConnectWallet,
  WalletIcon,
  ConnectWalletTip,
  ConnectWalletButton,
  Login,
  Subscribe,
  Loading,
  MessageContent,
  MessageStatus,
  NoMessage,
  MessageList,
  Footer,
} from "@cronosid/react-bell";

export const Modal = () => {
  const { isMobile, modalVisible } = useNotifiContext();

  return (
    <>
      {modalVisible ? (
        <div
          // add a className for the Modal
          className="cns"
          style={{
            maxWidth: isMobile ? undefined : "368px",
            width: "100%",
            height: isMobile ? "100vh" : "640px",
            position: isMobile ? "fixed" : "absolute",
            left: 0,
            top: isMobile ? 0 : "110px",
          }}
        >
          <NotificationContainer>
            <Header />
            <CloseButton />
            <NotificationContent>
              <ErrorTipContent />
              <ConnectWallet>
                <WalletIcon />
                <ConnectWalletTip />
                <ConnectWalletButton
                  connectWallet={async () => {
                    // the function to connect the wallet
                    await currentWallet.connect();
                  }}
                />
              </ConnectWallet>
              <Login />
              <Subscribe />
              <Loading />
              <MessageContent>
                {/* the tg bind tip, if don't pass the tgInfo, it doesn't display even you pass it */}
                {/* <ConnectTgTip /> */}
                <MessageStatus />
                <NoMessage />
                <MessageList />
              </MessageContent>
            </NotificationContent>
            <Footer />
          </NotificationContainer>
        </div>
      ) : null}
    </>
  );
};

The above 👆 demo is the simple version and does not require customization. If wanna customize the SDK, please go ahead.

Customization

The SDK is the Compound React Components, we can combine the components at will.

So we can do the customized component as we want. If a component has a children props, we can pass the component or string to customize it. If we don't pass children it will have the default component.

Customization Demos

Customize the BellButton Icon

<BellButton>
  <YourIcon />
</BellButton>

Customize the CloseButton Icon

<CloseButton>
  <YourIcon />
</CloseButton>

Customize the ErrorTipContent tip

<ErrorTipContent>
  <YourErrorTip />
</ErrorTipContent>

Customize the NoMessage tip

<NoMessage>
  <NoMessageTip>
    <Text color={"#999"}>No notifications yet</Text>
  </NoMessageTip>
</NoMessage>

Customize the ConnectWallet tip

<ConnectWallet>
  <YourWalletIcon />
  <YourConnectWalletTip />
  {/* or */}
  {/* <ConnectWalletTip>
    Your connect tip here
  </ConnectWalletTip> */}
  <ConnectWalletButton
    connectWallet={async () => {
      // the function to connect the wallet
      await currentWallet.connect();
    }}
  />
</ConnectWallet>

Customize the MessageStatus tip.

Here we just wanna customize a SettingIcon but we should pass all the children components. If we don't do that, the missing component won't display.

<MessageStatus>
  <HasUnreadMessages />
  <NoUnreadMessages />
  {/* the setting icon */}
  <SettingButton>
    <SettingIcon />
  </SettingButton>
</MessageStatus>

Customize the success tip for ConnectTgTip and TgBind, please know we should pass all the children component.

const tgBindBtn = (
  <>
    <TgBindButton>
      <TgUnbindTip />
      <TgBindSuccess>
        <YourTgBoundTip>
          <Icon />
          <Text ml={"2px"}>Account Bound</Text>
        </YourTgBoundTip>
      </TgBindSuccess>
      <TgBindErrorTip />
    </TgBindButton>
  </>
);

<ConnectTgTip>
  <ConnectTgTipBody>
    <ConnectTgTipTitle />
    {tgBindBtn}
  </ConnectTgTipBody>
  <ConnectTgTipCloseIcon />
</ConnectTgTip>;
<TgBind>
  <TgBindTitle />
  <TgBindBody>
    <TgBindInfo>
      <TgBindSubTitle />
      <TgBindDescription />
    </TgBindInfo>
    <TgBindButtonAlignRight>{tgBindBtn}</TgBindButtonAlignRight>
  </TgBindBody>
</TgBind>
Code Example

There is a full demo for customization

import {
  Box,
  Drawer,
  DrawerContent,
  DrawerOverlay,
  Text,
} from "@chakra-ui/react";
import {
  Header,
  Footer,
  CloseButton,
  MessageStatus,
  ConnectTgTip,
  ConnectTgTipBody,
  ConnectTgTipTitle,
  ConnectTgTipCloseIcon,
  SettingButton,
  MessageContent,
  NotificationContainer,
  NotificationContent,
  NoMessage,
  ConnectWallet,
  Login,
  Subscribe,
  MessageList,
  useNotifiContext,
  Loading,
  SettingContent,
  TgBind,
  TgBindTitle,
  TgBindBody,
  TgBindInfo,
  TgBindSubTitle,
  TgBindDescription,
  TgBindButtonAlignRight,
  TgBindButton,
  TgUnbindTip,
  TgBindErrorTip,
  TgBindSuccess,
  UnsubscribeChannel,
  ErrorTipContent,
  ConnectWalletTip,
  ConnectWalletButton,
  LoginButton,
  LoginTip,
  MessagesPlaceholder,
  SubscribeAction,
  SubscribeTip,
  SubscribeButton,
  NoMessageTip,
  HasUnreadMessages,
  NoUnreadMessages,
  LoadingAnimation,
  LoadingTip,
} from "@cronosid/react-bell";
import type { Message } from "@cronosid/react-bell";

const tgBindBtn = (
  <>
    <TgBindButton>
      <TgUnbindTip />
      <TgBindSuccess>
        <YourTgBoundTip>
          <Icon />
          <Text ml={"2px"}>Account Bound</Text>
        </YourTgBoundTip>
      </TgBindSuccess>
      <TgBindErrorTip />
    </TgBindButton>
  </>
);

export const ModalDrawer = () => {
  const { isMobile, modalVisible, setModalVisible } = useNotifiContext();

  return (
    <>
      <Drawer
        isOpen={modalVisible}
        onClose={() => setModalVisible(false)}
        placement="right"
        autoFocus={false}
        size={"sm"}
      >
        <DrawerOverlay />
        <DrawerContent>
          <div
            // add a className
            className="cns"
            style={{
              width: "100%",
              height: "100vh",
            }}
          >
            <NotificationContainer>
              <Header />
              <CloseButton>
                <YourIcon />
              </CloseButton>
              <NotificationContent>
                <ErrorTipContent>
                  <YourErrorTip />
                </ErrorTipContent>
                <ConnectWallet>
                  {/* <YourWalletIcon /> */}
                  <ConnectWalletTip />
                  <ConnectWalletButton
                    connectWallet={async () => {
                      await currentWallet.connect();
                    }}
                  />
                </ConnectWallet>
                <Login>
                  {/* <YourBellIcon /> */}
                  <LoginTip>
                    Please review and accept the{" "}
                    <Text as="span" color={"#00D5D1"}>
                      <Link
                        href={
                          "https://docs.cronosid.xyz/what-is-cronos-id/cronos-id-notifications/terms-and-conditions"
                        }
                        target="_blank"
                        rel="noopener noreferrer"
                      >
                        terms
                      </Link>{" "}
                    </Text>
                    to start using our notification service.
                  </LoginTip>
                  <LoginButton>Accept the Terms</LoginButton>
                </Login>
                <Subscribe>
                  <MessagesPlaceholder>
                    {[0, 1, 2].map((i) => (
                      <Box px={4} py={2} key={i}>
                        a lot of messages
                      </Box>
                    ))}
                  </MessagesPlaceholder>
                  <SubscribeAction>
                    <SubscribeTip>
                      Subscribe to this channel so you don&apos;t miss important
                      updates of the protocol, your trades, and more!
                    </SubscribeTip>
                    <SubscribeButton />
                  </SubscribeAction>
                </Subscribe>
                <Loading>
                  {/* if wanna customize the loading content, pass the conte to it, if don't just ignore it */}
                  {/*
                    <YourLoadingAnimation />
                    <YourLoadingTip />
                  */}
                </Loading>
                <MessageContent>
                  <ConnectTgTip>
                    <ConnectTgTipBody>
                      <ConnectTgTipTitle />
                      {tgBindBtn}
                    </ConnectTgTipBody>
                    <ConnectTgTipCloseIcon />
                  </ConnectTgTip>
                  <MessageStatus>
                    <HasUnreadMessages />
                    <NoUnreadMessages />
                    {/* the setting icon */}
                    <SettingButton>
                      <SettingIcon />
                    </SettingButton>
                  </MessageStatus>
                  <NoMessage>
                    <NoMessageTip>
                      <Text color={"#999"}>No notifications yet</Text>
                    </NoMessageTip>
                  </NoMessage>
                  <MessageList
                    renderItem={(
                      message: Message,
                      index?: number,
                      messageLength?: number
                    ) => {
                      return (
                        <div
                          key={message.id}
                          style={{
                            padding: "10px",
                            backgroundColor: "#11101B",
                            borderRadius: "12px",
                            margin: "8px 0",
                          }}
                        >
                          <p>{message.is_read ? "" : "unread"}</p>
                          <h3>{message.title}</h3>
                          <p>{message.body}</p>
                        </div>
                      );
                    }}
                  />
                </MessageContent>
                <SettingContent>
                  <TgBind>
                    <TgBindTitle />
                    <TgBindBody>
                      <TgBindInfo>
                        <TgBindSubTitle />
                        <TgBindDescription />
                      </TgBindInfo>
                      <TgBindButtonAlignRight>
                        {tgBindBtn}
                      </TgBindButtonAlignRight>
                    </TgBindBody>
                  </TgBind>
                  <UnsubscribeChannel />
                </SettingContent>
              </NotificationContent>
              <Footer />
            </NotificationContainer>
          </div>
        </DrawerContent>
      </Drawer>
    </>
  );
};

The CSS Style Override

If you wanna change the UI design and the styling should be consistent with your current UI. We can change the CSS style by overriding the CSS.

Importing a CSS file into your code

CSS Style Example
.cns .cns-container {
  background: #0c0c0c;
  border-radius: 0;
}
.cns .header {
  padding: 20px 16px;
}
.cns .header h4 {
  font-size: 16px;
  line-height: 24px;
}
.cns .footer {
  background: #0c0c0c;
}

.cns .subscribe-action {
  background: linear-gradient(
    180deg,
    rgba(12, 12, 12, 0.7) 0%,
    rgba(12, 12, 12, 1) 100%
  );
  padding-bottom: 50%;
}

.cns .btn {
  min-width: auto;
  background: #574be8;
  border-radius: 8px;
  padding: 16px 12px;
}
.cns .btn:not(:disabled):hover {
  background: #fff;
  color: #000;
}

.cns .message-status {
  margin-top: 8px;
  background-color: #11101b;
  border: none;
  border-radius: 12px;
  font-size: 12px;
}
.cns .message-status .mark-all-read {
  color: #8c82ff;
  font-size: 14px;
}

.cns .connect-tg-tip-title {
  font-size: 12px;
  font-weight: 600;
}
.cns .tg-bind-success,
.cns .tg-bind-error,
.cns .tg-unbind-tip {
  font-weight: 400;
  font-size: 12px;
}
.cns .tg-bind-success {
  color: #38de8c;
}
.cns .tg-unbind-tip {
  color: #ff9d00;
}

.cns .login-tip {
  margin-top: 8px;
}

.cns .connect-tg-tip {
  border-bottom: none;
  background: linear-gradient(175deg, #0c0c0c 0%, #243952 49%, #318b7b 120%);
}

.cns .setting-tg-bind-title {
  font-size: 16px;
}
.cns .setting-tg-bind-subtitle {
  font-size: 14px;
}
.cns .setting-tg-bind-description {
  font-size: 11px;
  font-weight: 300;
  color: #ededed;
}
.cns .notify-types h4 {
  font-size: 16px;
}
.cns .notify-types p {
  font-size: 14px;
  color: #ededed;
}

.cns .unsubscribe-button {
  color: #ee316a;
  font-size: 14px;
  padding-top: 20px;
}
.cns .footer {
  /* border-top: none; */
}

The above 👆 just a demo, you can change it apply to your current UI design. The components have a className you can choose a component to override it.

Last updated