ACCESS-specific wrapper around @snf/qa-bot-core
npm install @snf/access-qa-botA React wrapper around @snf/qa-bot-core that adds ACCESS-specific functionality. This package serves two purposes:
1. Production use: The official Q&A bot for ACCESS websites
2. Reference implementation: An example of how to build organization-specific wrappers around qa-bot-core
``bash`
npm install @snf/access-qa-bot
- 🤖 Intelligent Q&A: AI-powered responses about ACCESS resources and services
- 🎫 Support Tickets: Create help tickets for general support, ACCESS login issues, and resource provider login problems
- 🔒 Security Reporting: Report security incidents with priority levels and file attachments
- 📊 Metrics/XDMoD: Query usage and performance data for ACCESS resources
- 📎 File Attachments: Upload screenshots, logs, and documents with tickets
- 👤 User Pre-population: Auto-fill forms with user info when logged in
- 🎨 Theming: Customizable colors and branding via qa-bot-core
- ♿ Accessibility: Full screen reader support and keyboard navigation
- 📱 Responsive: Works on desktop and mobile devices
- Floating Mode (default): Chat button that opens/closes a floating window
- Embedded Mode: Always visible, embedded in page content
---
For React applications, import and use the component directly:
`tsx
import React, { useRef, useState } from 'react';
import { AccessQABot } from '@snf/access-qa-bot';
function MyApp() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [chatOpen, setChatOpen] = useState(false);
const botRef = useRef();
return (
isLoggedIn={isLoggedIn}
open={chatOpen}
onOpenChange={setChatOpen}
userEmail="user@example.com"
userName="Jane Doe"
accessId="jdoe"
apiKey={process.env.VITE_API_KEY}
/>
#### React Props
| Property | Type | Default | Description |
|----------|------|---------|-------------|
|
isLoggedIn | boolean | false | User login state (gates Q&A, shows login/user icon) |
| apiKey | string | "demo-key" | API key for authentication |
| embedded | boolean | false | Embedded or floating mode |
| loginUrl | string | "/login" | Login redirect URL |
| open | boolean | - | Control chat window (floating mode) |
| onOpenChange | function | - | Chat window state callback |
| onAnalyticsEvent | function | - | Analytics event callback (receives core + wrapper events) |
| welcome | string | - | Custom welcome message |
| userEmail | string | - | Pre-populate email in forms |
| userName | string | - | Pre-populate name in forms |
| accessId | string | - | Pre-populate ACCESS ID in forms |
| actingUser | string | - | Acting user identifier forwarded to backend as X-Acting-User header |#### Ref Methods
`tsx
const botRef = useRef(null);// Add a message programmatically
botRef.current?.addMessage("Hello from code!");
`---
$3
For plain HTML/JS, use the self-contained standalone bundle:
`html
`#### Programmatic Control
The
qaBot() function returns a controller object:`javascript
const bot = qaBot({
target: document.getElementById('qa-bot'),
isLoggedIn: false,
});// Add messages
bot.addMessage("Hello World!");
// Update login state
bot.setBotIsLoggedIn(true);
// Control chat window (floating mode only)
bot.openChat();
bot.closeChat();
bot.toggleChat();
// Cleanup
bot.destroy();
`#### Standalone Config
| Property | Type | Default | Description |
|----------|------|---------|-------------|
|
target | HTMLElement | required | DOM element to render into |
| apiKey | string | "demo-key" | API key for authentication |
| defaultOpen | boolean | false | Initial chat window state |
| embedded | boolean | false | Embedded or floating mode |
| isLoggedIn | boolean | false | User login state |
| loginUrl | string | "/login" | Login redirect URL |
| onAnalyticsEvent | function | - | Analytics event callback |
| welcome | string | - | Welcome message |
| userEmail | string | - | Pre-populate email |
| userName | string | - | Pre-populate name |
| accessId | string | - | Pre-populate ACCESS ID |
| actingUser | string | - | Acting user identifier forwarded to backend as X-Acting-User header |---
$3
#### unpkg (npm-based)
`html
`#### jsdelivr (GitHub-based)
`html
`---
Building Your Own Wrapper
This repository demonstrates the wrapper pattern for extending qa-bot-core with organization-specific functionality. Use this as a reference for building your own wrapper.
$3
`
YourWrapper (this pattern)
└── QABot (from @snf/qa-bot-core)
└── react-chatbotify
`$3
- Chat UI (floating/embedded modes)
- Q&A flow with feedback
- Login state management
- Theming and branding props
-
customFlow prop for extending functionality$3
- Organization-specific flows (tickets, security, etc.)
- Integration with your backend services (JIRA, APIs)
- Custom form validation and state management
- Environment-specific configuration
$3
| File | Purpose |
|------|---------|
|
src/components/AccessQABot.tsx | Main wrapper component - combines flows, passes props to core |
| src/flows/*.ts | Custom conversation flows using react-chatbotify format |
| src/utils/flow-context.ts | Form state management across flow steps |
| src/utils/ticket-api.ts | Backend integration (JIRA ticket submission) |
| src/standalone.tsx | Standalone JS API wrapper |
| src/config/constants.ts | Environment config and defaults |$3
Flows use the react-chatbotify format:
`typescript
import { Flow } from 'react-chatbotify';export function createMyFlow(): Flow {
return {
my_start: {
message: "Hello! What would you like to do?",
options: ["Option A", "Option B"],
path: (params) => {
if (params.userInput === "Option A") return "option_a_step";
return "option_b_step";
},
},
option_a_step: {
message: "You chose A!",
path: "end",
},
// ... more steps
};
}
`$3
In your wrapper component:
`tsx
import { QABot, applyFlowSettings } from '@snf/qa-bot-core';const customFlow = useMemo(() => {
const flow1 = createMenuFlow();
const flow2 = createTicketFlow();
const flow3 = createMyCustomFlow();
const combined = { ...flow1, ...flow2, ...flow3 };
// Auto-set chatDisabled based on options/checkboxes
return applyFlowSettings(combined, { disableOnOptions: true });
}, [dependencies]);
return (
isLoggedIn={isLoggedIn}
customFlow={customFlow}
// ... other props
/>
);
`$3
qa-bot-core fires analytics events for core functionality (Q&A, ratings, open/close). Your wrapper can add its own events and forward everything to consumers.
1. Define a tracking function type:
`typescript
// src/utils/analytics.ts
export interface TrackEventInput {
type: string;
sessionId?: string;
timestamp?: number;
[key: string]: unknown;
}export type TrackEventFn = (event: TrackEventInput) => void;
`2. Accept
onAnalyticsEvent prop and create trackers:`tsx
// In your wrapper component
const trackEvent: TrackEventFn = useCallback((event) => {
if (onAnalyticsEvent) {
onAnalyticsEvent({
...event,
timestamp: event.timestamp ?? Date.now(),
sessionId: event.sessionId ?? sessionId,
});
}
}, [onAnalyticsEvent, sessionId]);// Handler for core events from qa-bot-core
const handleCoreAnalyticsEvent = useCallback((event) => {
if (onAnalyticsEvent) {
onAnalyticsEvent({
...event,
timestamp: typeof event.timestamp === 'number' ? event.timestamp : Date.now(),
sessionId: typeof event.sessionId === 'string' ? event.sessionId : sessionId,
});
}
}, [onAnalyticsEvent, sessionId]);
`3. Pass
trackEvent to your flow creators:`tsx
const customFlow = useMemo(() => {
const menuFlow = createMenuFlow({ trackEvent });
const ticketFlow = createTicketFlow({ trackEvent });
// ...
}, [trackEvent]);
`4. Wire up core analytics:
`tsx
onAnalyticsEvent={handleCoreAnalyticsEvent}
customFlow={customFlow}
// ...
/>
`5. Fire events in your flows:
`typescript
export function createTicketFlow({ trackEvent }: FlowParams) {
return {
ticket_submit: {
function: async (chatState) => {
const result = await submitTicket(data);
trackEvent({
type: 'ticket_submitted',
ticketType: 'general',
success: result.success,
});
},
// ...
},
};
}
`Consumers can then wire events to their analytics platform:
`tsx
onAnalyticsEvent={(event) => {
window.dataLayer?.push({ event: event.type, ...event });
}}
/>
`---
Environment Variables
Create
.env.local from .env.example:`env
VITE_API_ENDPOINT=https://your-qa-api.com/api/
VITE_RATING_ENDPOINT=https://your-qa-api.com/rating/
VITE_NETLIFY_BASE_URL=https://your-ticket-api.netlify.app
VITE_METRICS_API_ENDPOINT=https://your-metrics-api.com/
VITE_API_KEY=your_api_key_here
`Development
`bash
Install dependencies
npm installStart dev server
npm run devBuild all outputs (ESM, UMD, standalone)
npm run buildBuild library only (ESM, UMD)
npm run build:libType check
npm run type-check
`Build Outputs
| File | Format | Use Case |
|------|--------|----------|
|
dist/access-qa-bot.js | ESM | npm import (React apps) |
| dist/access-qa-bot.umd.cjs | UMD | CommonJS require |
| dist/access-qa-bot.standalone.js | IIFE | CDN/script tag (bundles Preact) |
| dist/style.css | CSS | Styles (auto-imported by standalone) |Version History
This package continues the
@snf/access-qa-bot npm package:| Version | Repository | Notes |
|---------|------------|-------|
| v0.x - v2.x | qa-bot (deprecated) | Original implementation |
| v3.0.0+ | access-qa-bot (this repo) | Rewrite using qa-bot-core |
$3
- Architecture: Now wraps @snf/qa-bot-core instead of embedding all logic
- TypeScript: Full TypeScript rewrite with type definitions
- Build: Vite-based build system (was Rollup + CRA)
- Props:
enabled → isLoggedIn` (breaking change)MIT