@wizlo/chat-widget
v1.0.7
Published
A chat widget for Wizlo client applications.
Readme
@wizlo/chat-widget
A comprehensive React-based chat widget component for Wizlo client applications with real-time messaging capabilities powered by Azure Communication Services (ACS).
🚀 Features
- 💬 Real-time messaging - Powered by Azure Communication Services
- 🎨 Customizable theming - Full control over colors and styling
- 📱 Responsive design - Works seamlessly on desktop and mobile
- ⚡ TypeScript support - Full type definitions included
- 🔒 Error boundaries - Graceful error handling and recovery
- ♿ Accessibility - WCAG compliant components
- 🎯 Redux integration - Built-in state management
- 🔧 Configurable menu - Customizable dropdown menu options
- 📊 Message history - Load and display conversation history
- 🛡️ Input validation - Built-in XSS protection and validation
📦 Installation
npm install @wizlo/chat-widgetPeer Dependencies
Ensure you have the required peer dependencies installed:
npm install react@>=16.8.0 react-dom@>=16.8.0CSS Imports
Import the widget styles in your application:
import '@wizlo/chat-widget/styles.css';🎯 Quick Start
Basic Implementation
import React, { useState } from 'react';
import { ChatWidget } from '@wizlo/chat-widget';
import '@wizlo/chat-widget/styles.css';
function App() {
const [authToken, setAuthToken] = useState('');
const [isAuthenticated, setIsAuthenticated] = useState(false);
// First, get the authentication token from your backend
const getAuthToken = async () => {
try {
const response = await fetch('https://your-backend.com/auth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: '[email protected]',
}),
});
const data = await response.json();
setAuthToken(data.accessToken);
setIsAuthenticated(true);
} catch (error) {
console.error('Authentication failed:', error);
}
};
const initParams = {
baseUrl: 'https://wizlo-backend.com',
authToken: authToken,
metaData: {
orderNo: 'ORD-12345',
},
};
const menuItems = [
{
label: 'End Chat',
action: () => console.log('Chat ended'),
icon: '🔚',
},
{
label: 'Transfer Chat',
action: () => console.log('Chat transferred'),
icon: '🔄',
},
];
if (!isAuthenticated) {
return (
<div>
<button onClick={getAuthToken}>Start Chat</button>
</div>
);
}
return (
<div className='app'>
<ChatWidget
initParams={initParams}
primaryColor='#007bff'
secondaryColor='#6c757d'
menuItems={menuItems}
showMenu={true}
/>
</div>
);
}
export default App;With Custom Redux Store
import React from 'react';
import { Provider } from 'react-redux';
import { ChatWidget } from '@wizlo/chat-widget';
import { store } from './store';
function App() {
return (
<Provider store={store}>
<ChatWidget
initParams={initParams}
primaryColor='#007bff'
secondaryColor='#6c757d'
menuItems={[]}
showMenu={false}
/>
</Provider>
);
}📚 API Reference
ChatWidget Props
| Prop | Type | Required | Description |
| ---------------- | --------------------- | -------- | -------------------------------------- |
| initParams | InitiateChatRequest | ✅ | API configuration and user information |
| primaryColor | string | ✅ | Primary theme color (hex format) |
| secondaryColor | string | ✅ | Secondary theme color (hex format) |
| menuItems | MenuItemConfig[] | ✅ | Dropdown menu configuration |
| showMenu | boolean | ✅ | Whether to show the dropdown menu |
InitiateChatRequest Interface
interface InitiateChatRequest {
baseUrl: string; // Wizlo backend API base URL
authToken: string; // Authentication token from your backend
metaData: {
orderNo: string; // Order/reference number
};
}MenuItemConfig Interface
interface MenuItemConfig {
label: string; // Display text
action: () => void; // Click handler function
icon?: string; // Optional icon (emoji or icon class)
}🎨 Theming & Customization
CSS Custom Properties
The widget uses CSS custom properties for theming. You can override these in your CSS:
:root {
--chat-primary-color: #007bff;
--chat-primary-hover: #0056b3;
--chat-background-color: #ffffff;
--chat-text-color: #333333;
--chat-border-color: #e0e0e0;
--chat-shadow-color: rgba(0, 0, 0, 0.1);
--chat-user-message-bg: #007bff;
--chat-agent-message-bg: #e9ecef;
--chat-input-bg: #ffffff;
--chat-header-bg: #007bff;
}Using StyleManager
import { StyleManager, applyDefaultTheme } from '@wizlo/chat-widget';
// Apply default theme
applyDefaultTheme();
// Or customize individual properties
const styleManager = StyleManager.getInstance();
styleManager.setProperty('primary-color', '#ff6b6b');
styleManager.setProperty('background-color', '#f8f9fa');
// Set multiple properties at once
styleManager.setTheme({
'primary-color': '#28a745',
'user-message-bg': '#28a745',
'header-bg': '#28a745',
});📁 Project Structure
@wizlo-chat-widget/
├── src/
│ ├── components/ # React components
│ │ ├── ChatWidget/ # Main widget component
│ │ ├── ChatContainer/ # Message container
│ │ ├── ChatHeader/ # Header with controls
│ │ ├── MessageList/ # Message display
│ │ ├── MessageInput/ # Input component
│ │ ├── MessageBubble/ # Individual message
│ │ ├── LoadingIndicator/# Loading states
│ │ ├── ErrorBoundary/ # Error handling
│ │ ├── ErrorDisplay/ # Error UI
│ │ ├── DropdownMenu/ # Menu component
│ │ ├── MenuButton/ # Menu button
│ │ ├── MenuItem/ # Menu items
│ │ └── StatusIndicator/ # Status display
│ ├── config/ # Configuration
│ │ ├── api.ts # API interfaces
│ │ └── constants.ts # Constants
│ ├── hooks/ # Custom hooks
│ │ ├── useChatInit.ts # Chat initialization
│ │ └── index.ts # Hook exports
│ ├── services/ # Business logic
│ │ ├── chatService.ts # Main chat service
│ │ ├── acs/ # Azure Communication Services
│ │ └── api/ # API services
│ ├── store/ # Redux store
│ │ ├── store.ts # Store configuration
│ │ └── slices/ # Redux slices
│ ├── styles/ # SCSS styles
│ │ ├── global.scss # Global styles
│ │ ├── reset.scss # CSS reset
│ │ └── components/ # Component styles
│ ├── types/ # TypeScript types
│ ├── utils/ # Utility functions
│ │ ├── dateUtils.ts # Date formatting
│ │ ├── validation.ts # Input validation
│ │ └── styleManager.ts # Theme management
│ └── index.ts # Main export
├── lib/ # Compiled output
├── tests/ # Test files
├── package.json # Package configuration
├── tsconfig.json # TypeScript config
├── rollup.config.cjs # Build configuration
└── README.md # This file🧪 Testing
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Run linting
npm run lint🏗️ Development
# Install dependencies
npm install
# Build the package
npm run build
# Build in watch mode
npm run build:watch
# Clean build artifacts
npm run clean📋 Requirements
- Node.js: >= 16.0.0
- npm: >= 8.0.0
- React: >= 16.8.0
- React DOM: >= 16.8.0
🌐 Browser Support
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
- Mobile browsers (iOS Safari, Chrome Mobile)
🔒 Security & Authentication
The widget includes built-in security features:
- XSS Protection: All user inputs are sanitized
- Input Validation: Message length and format validation
- Error Boundaries: Prevents crashes from propagating
- OAuth2 Authentication: Uses secure token-based authentication
- Token-based API Communication: All API calls use authentication tokens
Authentication Flow
The chat widget uses a secure authentication flow where your backend server obtains authentication tokens on behalf of users:
- Backend Token Generation: Your server requests tokens from the Wizlo authentication service
- Frontend Token Usage: Your frontend receives the token and passes it to the chat widget
- Secure Communication: All chat API calls use the authentication token
Backend Authentication Implementation
Create an authentication endpoint in your backend:
// auth.service.ts
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import axios from 'axios';
interface TokenRequest {
email: string;
}
interface TokenResponse {
accessToken: string;
}
@Injectable()
export class AuthService {
async getTokens(request: TokenRequest): Promise<TokenResponse> {
try {
const requestBody = {
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
user_email: request.email,
grant_type: 'client_credentials',
};
const response = await axios.post(
`${process.env.wizloBeUrl}/oauth/user-token`,
requestBody,
{
headers: {
'Content-Type': 'application/json',
},
}
);
return {
accessToken: response.data.access_token,
};
} catch (error) {
throw new HttpException('Authentication failed', HttpStatus.UNAUTHORIZED);
}
}
}// auth.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { AuthService } from './auth.service';
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@Post('token')
async getToken(@Body() request: TokenRequest): Promise<TokenResponse> {
return this.authService.getTokens(request);
}
}Frontend Authentication Implementation
Implement authentication in your frontend application:
import React, { useState } from 'react';
import { ChatWidget } from '@wizlo/chat-widget';
import '@wizlo/chat-widget/styles.css';
function App() {
const [authToken, setAuthToken] = useState('');
const [loading, setLoading] = useState(false);
const [showChat, setShowChat] = useState(false);
const authenticateAndStartChat = async () => {
setLoading(true);
try {
// Request authentication token from your backend
const response = await fetch('https://your-backend.com/auth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: '[email protected]',
}),
});
if (!response.ok) {
throw new Error('Authentication failed');
}
const { accessToken } = await response.json();
setAuthToken(accessToken);
setShowChat(true);
} catch (error) {
console.error('Authentication error:', error);
alert('Failed to authenticate. Please try again.');
} finally {
setLoading(false);
}
};
if (!showChat) {
return (
<div>
<button onClick={authenticateAndStartChat} disabled={loading}>
{loading ? 'Authenticating...' : 'Start Chat'}
</button>
</div>
);
}
const chatWidgetProps = {
initParams: {
baseUrl: 'https://wizlo-backend.com',
authToken: authToken,
metaData: {
orderNo: 'ORD-12345',
},
},
primaryColor: '#007bff',
secondaryColor: '#6c757d',
menuItems: [
{
label: 'End Chat',
action: () => setShowChat(false),
icon: '🔚',
},
],
showMenu: true,
};
return (
<div className='app'>
<ChatWidget {...chatWidgetProps} />
</div>
);
}
export default App;🚨 Error Handling
The widget provides comprehensive error handling:
// Error boundary catches component errors
<ErrorBoundary
onError={(error, errorInfo) => {
console.error('Chat widget error:', error, errorInfo);
}}
fallback={<CustomErrorComponent />}
>
<ChatWidget {...props} />
</ErrorBoundary>📈 Performance
- Code Splitting: Components are lazy-loaded where possible
- Memoization: React.memo used for expensive components
- Efficient Rendering: Redux selectors prevent unnecessary re-renders
- Bundle Size: Optimized build with tree-shaking
🤝 Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/new-feature - Make your changes and add tests
- Run tests:
npm test - Commit your changes:
git commit -am 'Add new feature' - Push to the branch:
git push origin feature/new-feature - Submit a pull request
📄 License
MIT License - see LICENSE file for details.
👥 Author
Wizlo Dev Team
Made with ❤️ for Wizlo
