@1saifj/novu-client
v1.2.0
Published
Custom Novu client library for React and Next.js
Downloads
49
Readme
@1saifj/novu-client
A modern React client library for Novu notification infrastructure with a beautiful Tailwind CSS UI and comprehensive theming options.
🌟 Features
- Modern API Client: Fully typed Novu API client with comprehensive endpoint coverage
- Real-time Support: WebSocket integration for instant notifications
- Beautiful UI: Clean, responsive Tailwind CSS components
- Flexible Theming: CSS variables and provider-based theming system
- Customizable UI: Replace any component with your own custom UI
- Pagination Support: Built-in "Load More" functionality
- TypeScript Ready: Full type definitions for a seamless developer experience
- React Hooks: Simple integration with functional components
📦 Installation
npm install @1saifj/novu-clientPeer Dependencies
This package requires the following peer dependencies:
npm install react react-dom🚀 Quick Start
Basic Usage
import React from 'react';
import { Inbox, NovuThemeProvider } from '@1saifj/novu-client';
function NotificationsComponent() {
return (
<NovuThemeProvider>
<Inbox
options={{
applicationIdentifier: 'YOUR_NOVU_APP_ID',
subscriberId: 'user-123',
backendUrl: 'https://api.novu.co/v1',
socketUrl: 'wss://ws.novu.co'
}}
onNotificationClick={(notification) => {
console.log('Notification clicked:', notification);
}}
onUnseenCountChanged={(count) => {
console.log('Unseen count:', count);
}}
/>
</NovuThemeProvider>
);
}🎨 Theming
Theme Customization
Customize the appearance by providing a theme object to the NovuThemeProvider:
import React from 'react';
import { Inbox, NovuThemeProvider } from '@1saifj/novu-client';
function ThemedNotifications() {
const theme = {
colors: {
primary: '#3B82F6', // Blue theme
secondary: '#1F2937',
grayLight: '#F9FAFB',
grayMedium: '#E5E7EB',
grayDark: '#6B7280',
success: '#10B981',
warning: '#F59E0B',
error: '#EF4444'
},
borderRadius: {
md: '0.375rem',
lg: '0.5rem',
},
container: {
maxWidth: '32rem',
maxHeight: '500px',
}
};
return (
<NovuThemeProvider theme={theme}>
<Inbox
options={{
applicationIdentifier: 'YOUR_NOVU_APP_ID',
subscriberId: 'user-123',
backendUrl: 'https://api.novu.co/v1',
socketUrl: 'wss://ws.novu.co'
}}
/>
</NovuThemeProvider>
);
}CSS Variables
You can also override the CSS variables directly in your CSS:
:root {
--novu-primary: #3B82F6;
--novu-secondary: #1F2937;
--novu-gray-light: #F9FAFB;
--novu-gray-medium: #E5E7EB;
--novu-gray-dark: #6B7280;
--novu-container-max-width: 32rem;
--novu-container-max-height: 500px;
--novu-border-radius-lg: 0.5rem;
}Class Name Overrides
Add custom classes to specific components:
const theme = {
classNameOverrides: {
inboxContainer: 'my-custom-inbox-container',
notification: 'my-custom-notification',
unseenNotification: 'my-custom-unseen',
loadingState: 'my-custom-loading',
emptyState: 'my-custom-empty',
button: 'my-custom-button'
}
};🛠️ Advanced Usage
Custom UI Components
Replace any part of the Inbox UI with your own components:
import React from 'react';
import { Inbox, NovuThemeProvider } from '@1saifj/novu-client';
function CustomizedInbox() {
return (
<NovuThemeProvider>
<Inbox
options={{
applicationIdentifier: 'YOUR_NOVU_APP_ID',
subscriberId: 'user-123',
backendUrl: 'https://api.novu.co/v1',
socketUrl: 'wss://ws.novu.co'
}}
headerComponent={
<div className="flex justify-between items-center p-4 border-b border-gray-200">
<h2 className="text-xl font-bold">My Notifications</h2>
<button className="text-blue-500 hover:text-blue-700">
Settings
</button>
</div>
}
emptyState={
<div className="flex flex-col items-center justify-center p-8 text-center">
<img src="/empty-state.svg" alt="No notifications" className="w-24 h-24 mb-4" />
<p className="text-gray-500">You're all caught up!</p>
</div>
}
footerComponent={
<div className="p-3 bg-gray-50 border-t border-gray-200 text-center">
<a href="/preferences" className="text-sm text-blue-500 hover:underline">
Manage notification preferences
</a>
</div>
}
/>
</NovuThemeProvider>
);
}Direct API Usage
Use the Novu client directly for custom integrations:
import { NovuClient } from '@1saifj/novu-client';
async function notificationService() {
// Initialize client
const client = new NovuClient({
backendUrl: 'https://api.novu.co/v1',
socketUrl: 'wss://ws.novu.co',
applicationIdentifier: 'YOUR_NOVU_APP_ID',
subscriberId: 'user-123'
});
// Start session
await client.initSession();
// Get notifications feed
const feed = await client.getNotificationFeed('user-123', {
page: 0,
limit: 10
});
// Mark message as read
await client.markMessageAs('user-123', {
messageId: 'message-id',
mark: { seen: true, read: true }
});
// Mark all messages as read
await client.markAllMessagesAs('user-123', {
markAs: 'read'
});
// Get subscriber preferences
const preferences = await client.getSubscriberPreferences('user-123');
// Get unseen count
const unseenCount = await client.getUnseenCount('user-123');
// Listen for real-time notifications
client.connectWebSocket();
client.onNotification((notification) => {
console.log('New notification:', notification);
});
}Solving CORS Issues
When using the library in a browser environment, you might encounter CORS issues when making requests to the Novu API. To solve this, you can use the proxyUrl option which routes requests through your own proxy server:
import React from 'react';
import { Inbox, NovuThemeProvider } from '@1saifj/novu-client';
function NotificationsComponent() {
return (
<NovuThemeProvider>
<Inbox
options={{
applicationIdentifier: 'YOUR_NOVU_APP_ID',
subscriberId: 'user-123',
backendUrl: 'https://api.novu.co/v1', // Original API URL
socketUrl: 'wss://ws.novu.co',
proxyUrl: '/api/novu-proxy' // Your proxy endpoint
}}
onNotificationClick={(notification) => {
console.log('Notification clicked:', notification);
}}
/>
</NovuThemeProvider>
);
}You can implement a simple proxy in Next.js:
// pages/api/novu-proxy/[...path].js
export default async function handler(req, res) {
const { path } = req.query;
const apiUrl = `https://api.novu.co/v1/${path.join('/')}`;
try {
const response = await fetch(apiUrl, {
method: req.method,
headers: {
...(req.headers.authorization && { 'Authorization': req.headers.authorization }),
'Content-Type': 'application/json'
},
body: req.method !== 'GET' && req.body ? JSON.stringify(req.body) : undefined
});
const data = await response.json();
return res.status(response.status).json(data);
} catch (error) {
return res.status(500).json({ error: 'Failed to proxy request' });
}
}📋 API Reference
Components
<NovuThemeProvider>
Provides theming context to all Novu components.
| Prop | Type | Description |
|------|------|-------------|
| theme | NovuTheme | Theme configuration object |
| children | ReactNode | Child components |
<Inbox>
The main notification inbox component.
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| options | object | ✅ | Configuration for the Novu client |
| options.applicationIdentifier | string | ✅ | Your Novu application ID |
| options.subscriberId | string | ✅ | Current user's subscriber ID |
| options.backendUrl | string | ✅ | Novu API URL |
| options.socketUrl | string | ✅ | Novu WebSocket URL |
| options.proxyUrl | string | | Optional proxy URL to bypass CORS issues |
| onNotificationClick | function | | Callback when a notification is clicked |
| onUnseenCountChanged | function | | Callback when unseen count changes |
| className | string | | Additional CSS class for the inbox container |
| headerComponent | ReactNode | | Custom header component |
| footerComponent | ReactNode | | Custom footer component |
| emptyState | ReactNode | | Custom empty state component |
| loadingState | ReactNode | | Custom loading state component |
Client Methods
NovuClient
| Method | Parameters | Return Type | Description |
|--------|------------|-------------|-------------|
| constructor | NovuOptions | NovuClient | Creates a new client instance with options including proxyUrl for CORS handling |
| initSession | subscriberId?: string | Promise<any> | Initialize a session with the Novu API |
| connectWebSocket | | any | Connect to the Novu WebSocket for real-time updates |
| onNotification | callback: (notification: Message) => void | void | Register a callback for real-time notifications |
| getNotificationFeed | subscriberId: string, options?: object | Promise<FeedResponse> | Get notification feed for a subscriber |
| getUnseenCount | subscriberId: string, feedIdentifier?: string | Promise<UnseenCountResponse> | Get count of unseen notifications |
| markMessageAs | subscriberId: string, options: MarkMessagesOptions | Promise<any> | Mark a message as read/unread or seen/unseen |
| markAllMessagesAs | subscriberId: string, options: MarkAllMessagesOptions | Promise<any> | Mark all messages with a specific status |
| updateOnlineStatus | subscriberId: string, status: OnlineStatusUpdate | Promise<Subscriber> | Update subscriber's online status |
| getSubscriberPreferences | subscriberId: string | Promise<Preferences[]> | Get subscriber's notification preferences |
| updateSubscriberPreferences | subscriberId: string, templateId: string, preferences: SubscriberPreference | Promise<Preferences> | Update subscriber's preferences |
Types
NovuTheme
interface NovuTheme {
colors?: {
primary?: string;
secondary?: string;
grayLight?: string;
grayMedium?: string;
grayDark?: string;
success?: string;
warning?: string;
error?: string;
};
spacing?: {
1?: string;
2?: string;
3?: string;
4?: string;
8?: string;
};
borderRadius?: {
sm?: string;
md?: string;
lg?: string;
full?: string;
};
typography?: {
fontSizeXs?: string;
fontSizeSm?: string;
fontSizeBase?: string;
fontSizeLg?: string;
fontWeightNormal?: number;
fontWeightMedium?: number;
fontWeightSemibold?: number;
};
shadow?: string;
container?: {
maxWidth?: string;
maxHeight?: string;
};
classNameOverrides?: {
inboxContainer?: string;
inboxHeader?: string;
notificationsList?: string;
notification?: string;
unseenNotification?: string;
loadingState?: string;
emptyState?: string;
button?: string;
};
}Message (Notification)
interface Message {
_id: string;
title?: string;
content: string;
seen: boolean;
read: boolean;
createdAt: string;
templateId?: string;
payload?: Record<string, any>;
cta?: {
type: string;
data: Record<string, any>;
};
[key: string]: any;
}💡 Tips & Best Practices
Theme Provider: Always wrap your Novu components with
NovuThemeProviderto ensure proper styling, even if you're not customizing the theme.Error Handling: Implement proper error handling around API calls to gracefully handle network issues.
Subscriber ID: Make sure to use consistent subscriber IDs across your application to ensure notifications are properly associated with users.
Performance: If you have a large number of notifications, consider implementing virtualized lists for better performance.
Authentication: Ensure you have proper authentication for your Novu API calls in production.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
Built with ❤️ by @1saifj
