ajaxter-chat
v3.2.0
Published
Drawer/popup/inline chat widget with real-time Socket.IO, WebRTC calling, voice messages, tickets, and display-mode config from server.
Maintainers
Readme
ajaxter-chat
A production-ready drawer/slider-based chat widget for React.js and Next.js (App Router and Pages Router). All configuration is loaded remotely from your hosted chatData.json.
| Audience | Where to start |
|----------|----------------|
| Frontend (React / Next.js embed) | This file — install, env vars, chatData.json, and usage below. |
| Backend (APIs, WebSockets, auth, payloads) | BACKEND.md — ChatMessage, tickets, presence, viewer blocked, WebRTC signalling, and recommended REST/socket shapes. |
Install
npm install ajaxter-chatPeer dependencies: React ≥ 17 and react-dom.
Environment variables (2 only)
Create React App / Vite (.env)
REACT_APP_CHAT_API_KEY=demo1234
REACT_APP_CHAT_WIDGET_ID=demoNext.js (.env.local)
NEXT_PUBLIC_CHAT_API_KEY=demo1234
NEXT_PUBLIC_CHAT_WIDGET_ID=demoRemote config URL
The widget fetches config from:
GET https://window.mscorpres.com/TEST/chatData.jsonWith headers:
X-Chat-Api-Key: demo1234
X-Chat-Widget-Id: demoOptional widget flags for spam-blocked viewers (see BACKEND.md): widget.viewerBlocked, or per-user viewerBlocked on the matching users / developers row for the logged-in uid, plus blockedViewerMessage, reenableRequestUrl.
Browser permissions: On first use (per tab), the widget asks for microphone, location, and screen capture (for voice, calls, and verification). If anything is denied, access is blocked until the user fixes site permissions and taps Try again. Successful grants are remembered for the session. Use HTTPS so geolocation works.
Presence (ACTIVE / AWAY / DND): Set widget.presenceUpdateUrl to your API; each change sends POST JSON { widgetId, apiKey, viewerUid?, status } for DB storage. Include widget.presenceStatus in chatData.json (from your DB) so the UI matches the server after reload.
chatData.json schema
Host this file at the URL above:
{
"widget": {
"id": "demo",
"apiKey": "demo1234",
"status": "ACTIVE",
"chatType": "BOTH",
"primaryColor": "#2563EB",
"buttonLabel": "Support",
"buttonPosition": "bottom-right",
"welcomeTitle": "Hi there 👋",
"welcomeSubtitle": "Need help? Start a conversation:",
"allowVoiceMessage": true,
"allowAttachment": true,
"allowEmoji": true,
"allowWebCall": true,
"maxEmojiCount": 20,
"allowTranscriptDownload": true,
"allowReport": true,
"allowBlock": true
},
"developers": [ { "uid":"dev_001","name":"...","type":"developer","status":"online", ... } ],
"users": [ { "uid":"usr_001","name":"...","type":"user","status":"online", ... } ],
"sampleChats": { "dev_001": [ { "id":"msg_001","senderId":"me","text":"Hi!","type":"text", ... } ] },
"sampleTickets": [ { "id":"TKT-0001","title":"...","status":"open","priority":"high", ... } ],
"blockedUsers": []
}Usage
React.js (CRA, Vite, or any React app)
import { ChatWidget } from 'ajaxter-chat';
import type { ChatWidgetViewer } from 'ajaxter-chat';
const viewer: ChatWidgetViewer = {
uid: 'usr_001',
name: 'Ravi Kumar',
type: 'user', // or 'developer' — controls Support vs staff UI
projectId: 'Client Portal', // optional; exact match to `project` in chatData users
};
export default function App() {
return (
<>
<main>App</main>
<ChatWidget viewer={viewer} />
</>
);
}Omit viewer to rely on viewerUid / viewerType from remote chatData.json only.
Next.js — App Router
ChatWidget uses browser APIs; import it only from a Client Component ('use client').
// app/ChatWidgetWrapper.tsx
'use client';
import { ChatWidget } from 'ajaxter-chat';
export function ChatWidgetWrapper() {
return <ChatWidget />;
}// app/layout.tsx
import { ChatWidgetWrapper } from './ChatWidgetWrapper';
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<ChatWidgetWrapper />
</body>
</html>
);
}Next.js — Pages Router
// pages/_app.tsx
import type { AppProps } from 'next/app';
import { ChatWidget } from 'ajaxter-chat';
export default function MyApp({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
<ChatWidget />
</>
);
}A minimal App Router proxy route example lives at examples/next-app-router-chat-proxy.ts (optional pattern for server-side forwarding).
Features
| Feature | Details |
|---|---|
| Drawer/Slider UI | Slides in from right (or left) with smooth animation. |
| Home Screen | "Hi there 👋" hero, cards for Support / New Conversation / Raise Ticket |
| User List | Slide-in panel with online status dot, designation, project |
| Chat Screen | Matches the UI image — hamburger back, title "Support", phone + fullscreen icons |
| Enter Your Details | Blue card at top of chat (ticket chat body placeholder) |
| Voice Messages | Record via MediaRecorder API, shows duration |
| Attachments | File picker, shows filename + size as message |
| Emoji Picker | 20 curated emojis, limited count via maxEmojiCount |
| Pause Chat | Developer can pause — user cannot send messages |
| Resume Chat | One-click resume from banner or menu |
| Report Chat | Flags chat, shows warning banner |
| Block User | Blocks users only (not developers), with confirm dialog |
| Block List Tab | View all blocked users, one-click unblock |
| Download Transcript | Saves plain-text .txt file of full conversation |
| WebRTC Calls | Secure P2P voice/video call with mute + camera toggle |
| Ticket Screen | Raise tickets with title, description, priority selector |
| Ticket History | Shows all tickets with status badge and priority color |
| Recent Chats Tab | Shows past conversations with unread badges |
| Responsive width | ~30% width on desktop; full width on small screens |
| Slide Close | Smooth slide-out animation on close |
| SSR Safe | isMounted guard, works in Next.js App Router and Pages Router |
| CHAT_STATUS | ACTIVE / DISABLE / MAINTENANCE handled |
WebSocket integration points
In src/hooks/useChat.ts — find the // TODO: comments:
// In selectUser:
// socket.emit('join', { roomId: user.uid });
// socket.on('message', msg => setMessages(prev => [...prev, msg]));
// In sendMessage:
// socket.emit('message', msg);In src/hooks/useWebRTC.ts — find the // TODO: comments:
// ICE candidate: socket.emit('ice-candidate', { candidate, to: peer.uid });
// Offer: socket.emit('call-offer', { offer, to: peer.uid });
// Answer: socket.emit('call-answer', { answer, to: peer.uid });Full event naming and payloads for backend teams are in BACKEND.md.
Package layout (source)
src/
├── index.ts
├── types/index.ts
├── config/index.ts ← reads CHAT_API_KEY + CHAT_WIDGET_ID, fetches chatData.json
├── utils/theme.ts
├── utils/chat.ts ← transcript, avatarColor, formatTime, downloadText
├── hooks/
│ ├── useRemoteConfig.ts ← fetches chatData.json
│ ├── useChat.ts ← messages, pause, report
│ └── useWebRTC.ts ← P2P WebRTC calling
└── components/
├── ChatWidget.tsx ← Root drawer orchestrator
├── HomeScreen/
├── UserListScreen/
├── ChatScreen/ ← voice, attach, emoji, pause, report, block, transcript, call
├── CallScreen/ ← WebRTC video/audio UI
├── EmojiPicker/
├── TicketScreen/
├── RecentChatsScreen/
├── BlockList/
├── MaintenanceView/
└── Tabs/BottomTabs.tsx ← Home / Chats / Tickets / Blocked
public/
└── chatData.json ← Sample JSON — host at window.mscorpres.com/TEST/chatData.json