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'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