Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
@trycourier/react-inbox
Advanced tools
An in-app notification center list you can use to notify your users. Allows you to build high quality, flexible notification feeds very quickly. Each message supports the following events:
Opened
When the Inbox is opened and a message is in view, we will fire off opened
events. One event per message. We will not send > 1 opened per message.
Read/Unread
Clicked
If a message has a click action associated with it, we will track clicks in the Courier Studio. The message will have a hover effect if the message is clickable as seen below.
Archive
Requirement | Reason |
---|---|
Courier Inbox Provider
| Needed to link your Courier Inbox to the SDK |
Authentication
| Needed to view inbox messages that belong to a user. |
Courier React Provider
| Provides state, api connections, and context to the components. |
Inbox requires a backend to pull messages. This is all done through the CourierProvider and requires an account at Courier. To set up the Inbox you will need to install the Courier Provider from the integrations page. After installing the integration you will be provided with a Client Key that you will pass into the CourierProvider.
Install the following packages to get started:
yarn add @trycourier/react-provider
yarn add @trycourier/react-inbox
@trycourier/react-provider is a peer dependeny of @trycourier/react-inbox and must also be installed
We've released new subdomains to power Inbox and Toast. This migration only applies to Inbox and Toast users who applied our old URLs to their Content Security Policy.
Before | After | Usage |
---|---|---|
https://api.courier.com | https://api.courier.com | Brands and User Preferences |
wss://1x60p1o3h8.execute-api.us-east-1.amazonaws.com | wss://realtime.courier.com | Websockets |
https://fxw3r7gdm9.execute-api.us-east-1.amazonaws.com | https://inbox.courier.com | Inbox Messages |
In order for the Inbox
component to be placed in the dom you will need to use the CourierProvider
. This will handle context and give us access Courier's backend API.
Check here for more information on this concept.
//App.js
import { CourierProvider } from "@trycourier/react-provider";
import { Inbox } from "@trycourier/react-inbox";
function App() {
// YOUR_CLIENT_KEY is a public facing key and can be found at https://app.courier.com/integrations/courier
return (
<CourierProvider userId={yourUserId} clientKey={YOUR_CLIENT_KEY}>
<Inbox />
</CourierProvider>
);
}
The default CourierInbox
styles.
//App.js
import { Inbox } from "@trycourier/react-inbox";
import { CourierProvider } from "@trycourier/react-provider";
function App() {
return (
<CourierProvider userId={yourUserId} clientKey={yourClientKey}>
<Inbox />
</CourierProvider>
);
}
Example of a styled CourierInbox
.
//App.js
import { Inbox } from "@trycourier/react-inbox";
import { CourierProvider } from "@trycourier/react-provider";
const theme = {
header: {
background: "pink",
},
messageList: {
container: {
background: "pink",
},
},
footer: {
background: "pink",
},
message: {
container: {
background: "red",
"&.read": {
background: "green",
div: {
color: "white",
},
},
"&:not(.read):hover": {
background: "yellow",
},
},
},
};
function App() {
return (
<CourierProvider userId={yourUserId} clientKey={yourClientKey}>
<Inbox theme={theme} />
</CourierProvider>
);
}
You can control your branding from the Courier Studio
.
//App.js
import { Inbox } from "@trycourier/react-inbox";
import { CourierProvider } from "@trycourier/react-provider";
function App() {
return (
<CourierProvider
brandId={"BRAND_ID"}
userId={yourUserId}
clientKey={yourClientKey}
>
<Inbox />
</CourierProvider>
);
}
You can use raw data you can use to build whatever UI you'd like by utilizing our react-hooks package.
By default the Courier Provider does not have authentication enabled. This is intentional and is helpful in getting things up and running. All that is required initially is the clientKey and a userId.
Information about the clientKey and authentication configuration can be found at https://app.courier.com/integrations/courier
The recommended way of doing authentication with Courier Inbox is to generate a JWT token for each user using the inbox. You can learn more about how to issue a token here: https://www.courier.com/docs/reference/auth/issue-token/
The required scopes are the following:
read:messages
- so we can fetch the messageswrite:events
- so we can create events like read/unread/archive
An example payload to the issue-token
api looks like :
{
"scope": "user_id:MY_USER_ID read:messages write:events"
}
The token that is returned can then be used the following way:
//App.js
import { useState, useEffect } from "react";
import { CourierProvider } from "@trycourier/react-provider";
import { Inbox } from "@trycourier/react-inbox";
function App() {
const [authorization, setAuthorization] = useState();
useEffect(() => {
const response = await fetchAuthToken();
setAuthentication(response.token);
}, []);
return (
<CourierProvider userId={yourUserId} authorization={authorization}>
<Inbox />
</CourierProvider>
);
}
If you need your tokens to expire periodically you can pass an expires_in
property to the token generation.
{
"scope": "user_id:MY_USER_ID read:messages write:events",
"expires_in": "1h"
}
//App.js
import { useState, useEffect } from "react";
import { CourierProvider } from "@trycourier/react-provider";
import { Inbox } from "@trycourier/react-inbox";
function App() {
const [authorization, setAuthorization] = useState();
useEffect(() => {
const response = await fetchAuthToken();
setAuthorization(response.token);
const interval = setInterval(async () => {
const response = await fetchAuthToken();
setAuthorization(response.token);
}, 300000);
return () => clearInterval(interval);
}, []);
return (
<CourierProvider authorization={authorization}>
<Inbox />
</CourierProvider>
);
}
You can also provide an HMAC token to be used. This has been replaced with JWT tokens. Please use JWT over HMAC as JWT allows you to create fine grain scopes and HMAC does not.
HMAC allows you to generate a signature for each user you have in your system. It is a hash of your userId and your API Key.
import crypto from "crypto";
const computedUserHmac = crypto
.createHmac("sha256", apiKey)
.update(userId)
.digest("hex");
Make sure you DO NOT do this on your frontend because your API Key is private and you do not want to leak it. This HMAC should be genrated on the backend and either embedded in your frontend via SSR or you must have an API endpoint to return this value per user.
After you have this HMAC returned, you can provide it to the CourierProvider
property. This is typically done inside an api that returns user information. i.e. GET /user/:user-id
import { CourierProvider } from "@trycourier/react-provider";
import { Inbox } from "@trycourier/react-inbox";
const MyComponent = (props) => {
return (
<CourierProvider
userId={props.userId}
userSignature={props.computedUserHmac}
clientKey={process.env.COURIER_CLIENT_KEY}
>
<Inbox />
{props.children}
</CourierProvider>
);
};
interface IHeaderProps {
labels: InboxProps["labels"];
markAllAsRead: () => void;
messages: IInboxMessagePreview[];
title?: string;
unreadMessageCount?: number;
}
interface ITextBlock {
type: "text";
text: string;
}
interface IActionBlock {
type: "action";
text: string;
url: string;
}
interface IGetInboxMessagesParams {
tenantId?: string;
archived?: boolean;
from?: string | number;
limit?: number;
status?: "read" | "unread";
tags?: string[];
}
interface InboxProps {
tenantId?: string;
brand?: Brand;
className?: string;
defaultIcon?: false | string;
// start date of the inbox to fetch messages
from?: number;
isOpen?: boolean;
// allows different views with different filter params
views?: Array<{
id: string;
label: string;
params?: IGetInboxMessagesParams;
}>;
formatDate?: (isoDate: string) => string;
// html query selector to render the inbox into
appendTo?: string;
labels?: {
archiveMessage?: string;
backToInbox?: string;
closeInbox?: string;
emptyState?: string;
markAllAsRead?: string;
markAsRead?: string;
markAsUnread?: string;
scrollTop?: string | ((count: string) => string);
};
// event listener for events such as "read", "unread", "archive"
onEvent?: OnEvent;
openLinksInNewTab?: boolean;
// relative to the inbox beel
placement?: TippyProps["placement"];
showUnreadMessageCount?: boolean;
theme?: InboxTheme;
title?: string;
trigger?: TippyProps["trigger"];
renderContainer?: React.FunctionComponent;
renderBell?: React.FunctionComponent<{
className?: string;
isOpen: boolean;
onClick?: (event: React.MouseEvent) => void;
}>;
renderFooter?: React.FunctionComponent;
renderHeader?: React.FunctionComponent<IHeaderProps>;
renderPin?: React.FunctionComponent<PinDetails>;
renderIcon?: React.FunctionComponent<{
isOpen: boolean;
unreadMessageCount?: number;
}>;
renderMessage?: React.FunctionComponent<IInboxMessagePreview>;
renderNoMessages?: React.FunctionComponent;
}
You can add more views beyound the default "all messages" view. You can provide a few different filter params like archived
, status
, limit
, tags
, ect... to create the experience you are looking for. If you customize the views, you will overwrite the default view of:
{
"id": "messages",
"label": "Notifications"
}
so make sure to include this view if you want to include an all messages view.
useInbox
is a hook that you can import and use to interact with Inbox without having to use any of the react components. Think of it as a headless
Inbox.
See https://github.com/trycourier/courier-react/tree/main/packages/react-hooks
interface ITheme {
brand?: Brand;
container?: CSSObject;
emptyState?: CSSObject;
footer?: CSSObject;
header?: CSSObject;
menu?: CSSObject;
tooltip?: CSSObject;
icon?: CSSObject & {
open?: string;
closed?: string;
};
messageList?: {
container?: CSSObject;
scrollTop?: CSSObject;
};
message?: {
actionElement?: CSSObject;
actionMenu?: {
button?: CSSObject;
dropdown?: CSSObject;
};
clickableContainer?: CSSObject;
container?: CSSObject;
content?: CSSObject;
icon?: CSSObject;
textElement?: CSSObject;
timeAgo?: CSSObject;
title?: CSSObject;
unreadIndicator?: CSSObject;
};
root?: CSSObject;
unreadIndicator?: CSSObject;
}
Since we are themeing with CSSObject from styled components, there are some themes that you may need to target by specifiying classNames. For example, to theme the
read
message styling you would do:
const theme = {
message: {
container: {
"&.read": {
background: "red",
},
"&:not(.read):hover": {
background: "blue",
},
},
},
};
Render Props are a react concept that allows you to supply your own react components instead of the ones built for this library. Inbox supplies render props for most sub components.
To overrwrite the rendering of each of these you can supply your own react component.
// Render Props for Custom Rendering
renderBlocks?: {
action?: React.FunctionComponent<IActionBlock>;
text?: React.FunctionComponent<ITextBlock>;
};
renderContainer?: React.FunctionComponent;
renderBell?: React.FunctionComponent<{
className?: string;
isOpen?: boolean;
onClick?: (event: React.MouseEvent) => void;
onMouseEnter?: (event: React.MouseEvent) => void;
}>;
renderFooter?: React.FunctionComponent;
renderHeader?: React.FunctionComponent<IHeaderProps>;
renderPin?: React.FunctionComponent<PinDetails>;
renderIcon?: React.FunctionComponent<{
isOpen: boolean;
unreadMessageCount?: number;
}>;
renderMessage?: React.FunctionComponent<IMessage>;
renderNoMessages?: React.FunctionComponent;
Pinning is a new feature as of 3.6.0 that allows you to "pin" certain messages to the top of their inbox. The pins are configured into slots
by editing your brand in the Courier Studio or by passing in a brand object with the correct pin slots. A pin slot is defined as:
interface PinSlot {
id: string;
label: {
value?: string;
color?: string;
};
icon: {
value?: string;
color?: string;
};
}
The default Pin looks like:
They can be configured to look like:
You can override the styling of the Pin through css accessing theme?.message?.pinned
or by passing in a renderPin(pinSlot)
as a property to the component.
The classic styling of the inbox has been deprecated. You can find more information about the old styling here. In summary, you can access the old styling and non-breaking changes by installing the 2.0.1 version linked above for @trycourier/react-inbox
and @trycourier/react-provider
.
Updated Theme: Some of the main differences are the following:
The format of the message has changd, so if you have any code that utilizes any of the following you will need to update:
useInbox
. SeerenderMessage
or renderAction
This is a contrived example of the changes:
Note we are utilized our new elemental standard:
interface ActionBlock {
type: "text";
text: string;
url: string;
}
interface OldMessage {
title: string;
body: string;
read?: boolean;
blocks: Array<TextBlock | ActionBlock>;
}
interface ActionElement {
type: "text";
content: string;
href: string;
}
interface NewMessage {
title: string;
preview: string;
read?: string;
actions: Array<ActionElement>;
}
New Theme Properties:
theme.tooltip
: accesses background and colors of tooltipstheme.menu
: clicking on the inbox title opens a dropdown menu with options to edit preferences
theme.message.clickableContainer
: when a message has an action href, we now make the entire message clickable instead of rendering an explicit button. this theme property allows access to this component. theme.message.container
will still apply to this component but if you want to target the clickableContainer separatly you can target theme.message.clickableContainer
which will be an anchor
element instead of a div
;The inbox component accepts a function in property formatDate
of type (isoDate: string) => string;
. You can overwrite Courier's date formats on each message using formatDate
for use cases like internationalization and override the browser's default.
Example using date-fns:
import formatDistanceStrict from "date-fns/formatDistanceStrict";
import { Locale } from "date-fns";
const getTimeAgo = (created: string, locale: Locale) => {
return formatDistanceStrict(new Date(created).getTime(), Date.now(), {
addSuffix: true,
roundingMethod: "floor",
locale
})(created);
}
---
<Inbox
formatDate={isoDate=>getTimeAgo(isoDate, users_locale)}
>
You can listen to inbox events by passing onEvent prop to
type EventType = "read" | "unread" | "archive" | "click" | "mark-all-read" | "unpin";
interface IEventParams = {
message?: IInboxMessagePreview;
messageId?: string;
event: EventType;
}
type OnEvent = (params: IEventParams) => void;
FAQs
Unknown package
The npm package @trycourier/react-inbox receives a total of 19,117 weekly downloads. As such, @trycourier/react-inbox popularity was classified as popular.
We found that @trycourier/react-inbox demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.