@blockspark/chat-widget 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +209 -0
- package/dist/components/ChatWidget.d.ts +39 -0
- package/dist/components/ChatWidget.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.LICENSE.txt +9 -0
- package/dist/services/dialogflowClient.d.ts +35 -0
- package/dist/services/dialogflowClient.d.ts.map +1 -0
- package/dist/styles.css +461 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# BlockSpark Chat Widget
|
|
2
|
+
|
|
3
|
+
A reusable React chat widget component that connects directly with Dialogflow CX - no backend API required!
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Option 1: Install from Local Path (Recommended for Development)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# In your website project directory
|
|
11
|
+
npm install /path/to/blockspark-chat-widget
|
|
12
|
+
# or
|
|
13
|
+
npm install ../blockspark-chat-widget
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### Option 2: Use npm link (For Development)
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# In the blockspark-chat-widget directory
|
|
20
|
+
npm link
|
|
21
|
+
|
|
22
|
+
# In your website project directory
|
|
23
|
+
npm link @blockspark/chat-widget
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Option 3: Publish to npm (For Production)
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Build the library first
|
|
30
|
+
npm run build
|
|
31
|
+
|
|
32
|
+
# Publish to npm (make sure you're logged in)
|
|
33
|
+
npm publish
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then install in your project:
|
|
37
|
+
```bash
|
|
38
|
+
npm install @blockspark/chat-widget
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### Basic Usage
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import ChatWidget from '@blockspark/chat-widget';
|
|
47
|
+
import '@blockspark/chat-widget/dist/styles.css';
|
|
48
|
+
|
|
49
|
+
// Load your Google Cloud service account key
|
|
50
|
+
import serviceAccountKey from './path/to/service-account-key.json';
|
|
51
|
+
|
|
52
|
+
function App() {
|
|
53
|
+
return (
|
|
54
|
+
<div>
|
|
55
|
+
<ChatWidget
|
|
56
|
+
dfProjectId="your-project-id"
|
|
57
|
+
dfLocation="us-central1"
|
|
58
|
+
dfAgentId="your-agent-id"
|
|
59
|
+
serviceAccountKey={serviceAccountKey}
|
|
60
|
+
languageCode="en"
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Using Access Token (Alternative)
|
|
68
|
+
|
|
69
|
+
If you prefer to manage authentication yourself:
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import ChatWidget from '@blockspark/chat-widget';
|
|
73
|
+
import '@blockspark/chat-widget/dist/styles.css';
|
|
74
|
+
|
|
75
|
+
function App() {
|
|
76
|
+
const [accessToken, setAccessToken] = useState<string>('');
|
|
77
|
+
|
|
78
|
+
// Get access token from your backend or OAuth flow
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
// Your token fetching logic here
|
|
81
|
+
fetchAccessToken().then(setAccessToken);
|
|
82
|
+
}, []);
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<ChatWidget
|
|
86
|
+
dfProjectId="your-project-id"
|
|
87
|
+
dfLocation="us-central1"
|
|
88
|
+
dfAgentId="your-agent-id"
|
|
89
|
+
accessToken={accessToken}
|
|
90
|
+
languageCode="en"
|
|
91
|
+
/>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### With Custom Configuration
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import ChatWidget from '@blockspark/chat-widget';
|
|
100
|
+
import '@blockspark/chat-widget/dist/styles.css';
|
|
101
|
+
import serviceAccountKey from './service-account-key.json';
|
|
102
|
+
|
|
103
|
+
function App() {
|
|
104
|
+
return (
|
|
105
|
+
<ChatWidget
|
|
106
|
+
dfProjectId="your-project-id"
|
|
107
|
+
dfLocation="us-central1"
|
|
108
|
+
dfAgentId="your-agent-id"
|
|
109
|
+
serviceAccountKey={serviceAccountKey}
|
|
110
|
+
languageCode="en"
|
|
111
|
+
title="💬 My Chat Assistant"
|
|
112
|
+
subtitle="How can I help you?"
|
|
113
|
+
welcomeTitle="👋 Welcome!"
|
|
114
|
+
welcomeMessage="I'm here to help you with any questions."
|
|
115
|
+
welcomeCta="Start chatting"
|
|
116
|
+
showWelcomePopup={true}
|
|
117
|
+
welcomePopupDelay={2000}
|
|
118
|
+
inputPlaceholder="Type your message..."
|
|
119
|
+
emptyStateMessage="Hi! How can I help you today?"
|
|
120
|
+
debug={false}
|
|
121
|
+
/>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Import Types (TypeScript)
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
import ChatWidget, { ChatWidgetProps, DialogflowConfig } from '@blockspark/chat-widget';
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Props
|
|
133
|
+
|
|
134
|
+
| Prop | Type | Required | Default | Description |
|
|
135
|
+
|------|------|----------|---------|-------------|
|
|
136
|
+
| `dfProjectId` | `string` | Yes | - | Dialogflow project ID |
|
|
137
|
+
| `dfLocation` | `string` | No | `"us-central1"` | Dialogflow location |
|
|
138
|
+
| `dfAgentId` | `string` | Yes | - | Dialogflow agent ID |
|
|
139
|
+
| `serviceAccountKey` | `object` | Yes* | - | Google Cloud service account key JSON object |
|
|
140
|
+
| `accessToken` | `string` | Yes* | - | Access token (alternative to serviceAccountKey) |
|
|
141
|
+
| `languageCode` | `string` | No | `"en"` | Language code for Dialogflow |
|
|
142
|
+
| `title` | `string` | No | `"💬 BlockSpark AI Assistant"` | Chat widget title |
|
|
143
|
+
| `subtitle` | `string` | No | `"We're here to help"` | Chat widget subtitle |
|
|
144
|
+
| `welcomeTitle` | `string` | No | `"👋 Welcome to Blockspark"` | Welcome popup title |
|
|
145
|
+
| `welcomeMessage` | `string` | No | `"My name is BlockSpark..."` | Welcome popup message |
|
|
146
|
+
| `welcomeCta` | `string` | No | `"💬 Click here to start chatting!"` | Welcome popup CTA text |
|
|
147
|
+
| `showWelcomePopup` | `boolean` | No | `true` | Whether to show welcome popup |
|
|
148
|
+
| `welcomePopupDelay` | `number` | No | `1500` | Delay before showing welcome popup (ms) |
|
|
149
|
+
| `fallbackWelcomeMessage` | `string` | No | `"Hello! I'm BlockSpark..."` | Fallback message if API fails |
|
|
150
|
+
| `inputPlaceholder` | `string` | No | `"Type your message..."` | Input field placeholder |
|
|
151
|
+
| `emptyStateMessage` | `string` | No | `"Hi! I'm BlockSpark..."` | Empty state message |
|
|
152
|
+
| `debug` | `boolean` | No | `false` | Enable debug logging |
|
|
153
|
+
|
|
154
|
+
\* Either `serviceAccountKey` or `accessToken` must be provided.
|
|
155
|
+
|
|
156
|
+
## How It Works
|
|
157
|
+
|
|
158
|
+
The widget connects **directly** to Dialogflow CX using the REST API - no backend required!
|
|
159
|
+
|
|
160
|
+
1. **Authentication**: Uses Google Cloud service account key to generate OAuth2 access tokens
|
|
161
|
+
2. **Session Management**: Creates and manages Dialogflow sessions automatically
|
|
162
|
+
3. **Message Handling**: Sends messages directly to Dialogflow and displays responses
|
|
163
|
+
4. **Rich Content**: Supports Dialogflow rich content (chips, cards, etc.)
|
|
164
|
+
|
|
165
|
+
## Requirements
|
|
166
|
+
|
|
167
|
+
- React 16.8.0 or higher
|
|
168
|
+
- React DOM 16.8.0 or higher
|
|
169
|
+
- Google Cloud service account with Dialogflow API enabled
|
|
170
|
+
- Dialogflow CX agent
|
|
171
|
+
|
|
172
|
+
## Getting Your Service Account Key
|
|
173
|
+
|
|
174
|
+
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
|
175
|
+
2. Select your project
|
|
176
|
+
3. Navigate to **IAM & Admin** > **Service Accounts**
|
|
177
|
+
4. Create a new service account or select an existing one
|
|
178
|
+
5. Create a JSON key and download it
|
|
179
|
+
6. Enable **Dialogflow API** for your project
|
|
180
|
+
7. Grant the service account **Dialogflow API User** role
|
|
181
|
+
|
|
182
|
+
## Security Warning ⚠️
|
|
183
|
+
|
|
184
|
+
**Important**: Service account keys contain sensitive credentials.
|
|
185
|
+
|
|
186
|
+
- **For Development**: You can import the key directly (as shown in examples)
|
|
187
|
+
- **For Production**:
|
|
188
|
+
- **DO NOT** expose service account keys in client-side code
|
|
189
|
+
- Use a backend proxy to handle authentication
|
|
190
|
+
- Or use OAuth2 flow to get access tokens securely
|
|
191
|
+
- Consider using restricted service account keys with minimal permissions
|
|
192
|
+
|
|
193
|
+
## Development
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# Install dependencies
|
|
197
|
+
npm install
|
|
198
|
+
|
|
199
|
+
# Build for production
|
|
200
|
+
npm run build
|
|
201
|
+
|
|
202
|
+
# Watch mode for development
|
|
203
|
+
npm run dev
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
MIT
|
|
209
|
+
export NPM_TOKEN=your_token_here
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import "../styles/chatWidget.css";
|
|
2
|
+
export interface ChatWidgetProps {
|
|
3
|
+
/** Custom title for the chat widget */
|
|
4
|
+
title?: string;
|
|
5
|
+
/** Custom subtitle for the chat widget */
|
|
6
|
+
subtitle?: string;
|
|
7
|
+
/** Welcome popup title */
|
|
8
|
+
welcomeTitle?: string;
|
|
9
|
+
/** Welcome popup message */
|
|
10
|
+
welcomeMessage?: string;
|
|
11
|
+
/** Welcome popup CTA text */
|
|
12
|
+
welcomeCta?: string;
|
|
13
|
+
/** Whether to show the welcome popup */
|
|
14
|
+
showWelcomePopup?: boolean;
|
|
15
|
+
/** Delay in milliseconds before showing welcome popup */
|
|
16
|
+
welcomePopupDelay?: number;
|
|
17
|
+
/** Fallback welcome message if API fails */
|
|
18
|
+
fallbackWelcomeMessage?: string;
|
|
19
|
+
/** Placeholder text for input field */
|
|
20
|
+
inputPlaceholder?: string;
|
|
21
|
+
/** Custom empty state message */
|
|
22
|
+
emptyStateMessage?: string;
|
|
23
|
+
/** Enable/disable debug logging */
|
|
24
|
+
debug?: boolean;
|
|
25
|
+
/** Dialogflow project ID */
|
|
26
|
+
dfProjectId?: string;
|
|
27
|
+
/** Dialogflow location (e.g., "us-central1") */
|
|
28
|
+
dfLocation?: string;
|
|
29
|
+
/** Dialogflow agent ID */
|
|
30
|
+
dfAgentId?: string;
|
|
31
|
+
/** Google Cloud service account key JSON object */
|
|
32
|
+
serviceAccountKey?: any;
|
|
33
|
+
/** Access token (alternative to serviceAccountKey) */
|
|
34
|
+
accessToken?: string;
|
|
35
|
+
/** Language code for Dialogflow */
|
|
36
|
+
languageCode?: string;
|
|
37
|
+
}
|
|
38
|
+
export default function ChatWidget({ title, subtitle, welcomeTitle, welcomeMessage, welcomeCta, showWelcomePopup: enableWelcomePopup, welcomePopupDelay, fallbackWelcomeMessage, inputPlaceholder, emptyStateMessage, debug, dfProjectId, dfLocation, dfAgentId, serviceAccountKey, accessToken, languageCode, }: ChatWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
//# sourceMappingURL=ChatWidget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatWidget.d.ts","sourceRoot":"","sources":["../../src/components/ChatWidget.tsx"],"names":[],"mappings":"AAQA,OAAO,0BAA0B,CAAC;AAsBlC,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4BAA4B;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,yDAAyD;IACzD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4CAA4C;IAC5C,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iCAAiC;IACjC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mCAAmC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,GAAG,CAAC;IACxB,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EACjC,KAAoC,EACpC,QAA+B,EAC/B,YAAyC,EACzC,cAAyE,EACzE,UAA+C,EAC/C,gBAAgB,EAAE,kBAAyB,EAC3C,iBAAwB,EACxB,sBAAwF,EACxF,gBAAyC,EACzC,iBAAgF,EAChF,KAAa,EACb,WAAW,EACX,UAA0B,EAC1B,SAAS,EACT,iBAAiB,EACjB,WAAW,EACX,YAAmB,GACpB,EAAE,eAAe,2CA6bjB"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAChE,cAAc,6BAA6B,CAAC;AAC5C,cAAc,SAAS,CAAC;AAGxB,OAAO,UAAU,MAAM,yBAAyB,CAAC;AACjD,eAAe,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! For license information please see index.js.LICENSE.txt */
|
|
2
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.BlockSparkChatWidget=t(require("react")):e.BlockSparkChatWidget=t(e.React)}(this,e=>(()=>{"use strict";var t={12(t){t.exports=e},20(e,t,r){var s=r(12),o=Symbol.for("react.element"),n=Symbol.for("react.fragment"),a=Object.prototype.hasOwnProperty,i=s.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,c={key:!0,ref:!0,__self:!0,__source:!0};function l(e,t,r){var s,n={},l=null,d=null;for(s in void 0!==r&&(l=""+r),void 0!==t.key&&(l=""+t.key),void 0!==t.ref&&(d=t.ref),t)a.call(t,s)&&!c.hasOwnProperty(s)&&(n[s]=t[s]);if(e&&e.defaultProps)for(s in t=e.defaultProps)void 0===n[s]&&(n[s]=t[s]);return{$$typeof:o,type:e,key:l,ref:d,props:n,_owner:i.current}}t.Fragment=n,t.jsx=l,t.jsxs=l},848(e,t,r){e.exports=r(20)}},r={};function s(e){var o=r[e];if(void 0!==o)return o.exports;var n=r[e]={exports:{}};return t[e](n,n.exports,s),n.exports}s.d=(e,t)=>{for(var r in t)s.o(t,r)&&!s.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},s.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var o={};s.d(o,{default:()=>X});var n=s(848),a=s(12);const i=crypto,c=e=>e instanceof CryptoKey;class l extends Error{constructor(e,t){super(e,t),this.code="ERR_JOSE_GENERIC",this.name=this.constructor.name,Error.captureStackTrace?.(this,this.constructor)}}l.code="ERR_JOSE_GENERIC",class extends l{constructor(e,t,r="unspecified",s="unspecified"){super(e,{cause:{claim:r,reason:s,payload:t}}),this.code="ERR_JWT_CLAIM_VALIDATION_FAILED",this.claim=r,this.reason=s,this.payload=t}}.code="ERR_JWT_CLAIM_VALIDATION_FAILED",class extends l{constructor(e,t,r="unspecified",s="unspecified"){super(e,{cause:{claim:r,reason:s,payload:t}}),this.code="ERR_JWT_EXPIRED",this.claim=r,this.reason=s,this.payload=t}}.code="ERR_JWT_EXPIRED",class extends l{constructor(){super(...arguments),this.code="ERR_JOSE_ALG_NOT_ALLOWED"}}.code="ERR_JOSE_ALG_NOT_ALLOWED";class d extends l{constructor(){super(...arguments),this.code="ERR_JOSE_NOT_SUPPORTED"}}d.code="ERR_JOSE_NOT_SUPPORTED",class extends l{constructor(e="decryption operation failed",t){super(e,t),this.code="ERR_JWE_DECRYPTION_FAILED"}}.code="ERR_JWE_DECRYPTION_FAILED",class extends l{constructor(){super(...arguments),this.code="ERR_JWE_INVALID"}}.code="ERR_JWE_INVALID";class u extends l{constructor(){super(...arguments),this.code="ERR_JWS_INVALID"}}u.code="ERR_JWS_INVALID";class h extends l{constructor(){super(...arguments),this.code="ERR_JWT_INVALID"}}h.code="ERR_JWT_INVALID",class extends l{constructor(){super(...arguments),this.code="ERR_JWK_INVALID"}}.code="ERR_JWK_INVALID",class extends l{constructor(){super(...arguments),this.code="ERR_JWKS_INVALID"}}.code="ERR_JWKS_INVALID",class extends l{constructor(e="no applicable key found in the JSON Web Key Set",t){super(e,t),this.code="ERR_JWKS_NO_MATCHING_KEY"}}.code="ERR_JWKS_NO_MATCHING_KEY",Symbol.asyncIterator,class extends l{constructor(e="multiple matching keys found in the JSON Web Key Set",t){super(e,t),this.code="ERR_JWKS_MULTIPLE_MATCHING_KEYS"}}.code="ERR_JWKS_MULTIPLE_MATCHING_KEYS",class extends l{constructor(e="request timed out",t){super(e,t),this.code="ERR_JWKS_TIMEOUT"}}.code="ERR_JWKS_TIMEOUT",class extends l{constructor(e="signature verification failed",t){super(e,t),this.code="ERR_JWS_SIGNATURE_VERIFICATION_FAILED"}}.code="ERR_JWS_SIGNATURE_VERIFICATION_FAILED";const p=(e,t,r=0)=>{0===r&&(t.unshift(t.length),t.unshift(6));const s=e.indexOf(t[0],r);if(-1===s)return!1;const o=e.subarray(s,s+t.length);return o.length===t.length&&(o.every((e,r)=>e===t[r])||p(e,t,s+1))},m=e=>{switch(!0){case p(e,[42,134,72,206,61,3,1,7]):return"P-256";case p(e,[43,129,4,0,34]):return"P-384";case p(e,[43,129,4,0,35]):return"P-521";case p(e,[43,101,110]):return"X25519";case p(e,[43,101,111]):return"X448";case p(e,[43,101,112]):return"Ed25519";case p(e,[43,101,113]):return"Ed448";default:throw new d("Invalid or unsupported EC Key Curve or OKP Key Sub Type")}};async function y(e,t,r){if("string"!=typeof e||0!==e.indexOf("-----BEGIN PRIVATE KEY-----"))throw new TypeError('"pkcs8" must be PKCS#8 formatted string');return((e,t,r)=>(async(e,t,r,s,o)=>{let n,a;const c=new Uint8Array(atob(r.replace(e,"")).split("").map(e=>e.charCodeAt(0))),l="spki"===t;switch(s){case"PS256":case"PS384":case"PS512":n={name:"RSA-PSS",hash:`SHA-${s.slice(-3)}`},a=l?["verify"]:["sign"];break;case"RS256":case"RS384":case"RS512":n={name:"RSASSA-PKCS1-v1_5",hash:`SHA-${s.slice(-3)}`},a=l?["verify"]:["sign"];break;case"RSA-OAEP":case"RSA-OAEP-256":case"RSA-OAEP-384":case"RSA-OAEP-512":n={name:"RSA-OAEP",hash:`SHA-${parseInt(s.slice(-3),10)||1}`},a=l?["encrypt","wrapKey"]:["decrypt","unwrapKey"];break;case"ES256":n={name:"ECDSA",namedCurve:"P-256"},a=l?["verify"]:["sign"];break;case"ES384":n={name:"ECDSA",namedCurve:"P-384"},a=l?["verify"]:["sign"];break;case"ES512":n={name:"ECDSA",namedCurve:"P-521"},a=l?["verify"]:["sign"];break;case"ECDH-ES":case"ECDH-ES+A128KW":case"ECDH-ES+A192KW":case"ECDH-ES+A256KW":{const e=m(c);n=e.startsWith("P-")?{name:"ECDH",namedCurve:e}:{name:e},a=l?[]:["deriveBits"];break}case"Ed25519":n={name:"Ed25519"},a=l?["verify"]:["sign"];break;case"EdDSA":n={name:m(c)},a=l?["verify"]:["sign"];break;default:throw new d('Invalid or unsupported "alg" (Algorithm) value')}return i.subtle.importKey(t,c,n,o?.extractable??!1,a)})(/(?:-----(?:BEGIN|END) PRIVATE KEY-----|\s)/g,"pkcs8",e,t,r))(e,t,r)}const f=new TextEncoder,g=new TextDecoder;const w=e=>(e=>{let t=e;"string"==typeof t&&(t=f.encode(t));const r=[];for(let e=0;e<t.length;e+=32768)r.push(String.fromCharCode.apply(null,t.subarray(e,e+32768)));return btoa(r.join(""))})(e).replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_"),E=e=>{let t=e;t instanceof Uint8Array&&(t=g.decode(t)),t=t.replace(/-/g,"+").replace(/_/g,"/").replace(/\s/g,"");try{return(e=>{const t=atob(e),r=new Uint8Array(t.length);for(let e=0;e<t.length;e++)r[e]=t.charCodeAt(e);return r})(t)}catch{throw new TypeError("The input to be decoded is not correctly encoded.")}};function S(e,t="algorithm.name"){return new TypeError(`CryptoKey does not support this operation, its ${t} must be ${e}`)}function b(e,t){return e.name===t}function A(e){return parseInt(e.name.slice(4),10)}function _(e,t,...r){switch(t){case"HS256":case"HS384":case"HS512":{if(!b(e.algorithm,"HMAC"))throw S("HMAC");const r=parseInt(t.slice(2),10);if(A(e.algorithm.hash)!==r)throw S(`SHA-${r}`,"algorithm.hash");break}case"RS256":case"RS384":case"RS512":{if(!b(e.algorithm,"RSASSA-PKCS1-v1_5"))throw S("RSASSA-PKCS1-v1_5");const r=parseInt(t.slice(2),10);if(A(e.algorithm.hash)!==r)throw S(`SHA-${r}`,"algorithm.hash");break}case"PS256":case"PS384":case"PS512":{if(!b(e.algorithm,"RSA-PSS"))throw S("RSA-PSS");const r=parseInt(t.slice(2),10);if(A(e.algorithm.hash)!==r)throw S(`SHA-${r}`,"algorithm.hash");break}case"EdDSA":if("Ed25519"!==e.algorithm.name&&"Ed448"!==e.algorithm.name)throw S("Ed25519 or Ed448");break;case"Ed25519":if(!b(e.algorithm,"Ed25519"))throw S("Ed25519");break;case"ES256":case"ES384":case"ES512":{if(!b(e.algorithm,"ECDSA"))throw S("ECDSA");const r=function(e){switch(e){case"ES256":return"P-256";case"ES384":return"P-384";case"ES512":return"P-521";default:throw new Error("unreachable")}}(t);if(e.algorithm.namedCurve!==r)throw S(r,"algorithm.namedCurve");break}default:throw new TypeError("CryptoKey does not support this operation")}!function(e,t){if(t.length&&!t.some(t=>e.usages.includes(t))){let e="CryptoKey does not support this operation, its usages must include ";if(t.length>2){const r=t.pop();e+=`one of ${t.join(", ")}, or ${r}.`}else 2===t.length?e+=`one of ${t[0]} or ${t[1]}.`:e+=`${t[0]}.`;throw new TypeError(e)}}(e,r)}function v(e,t,...r){if((r=r.filter(Boolean)).length>2){const t=r.pop();e+=`one of type ${r.join(", ")}, or ${t}.`}else 2===r.length?e+=`one of type ${r[0]} or ${r[1]}.`:e+=`of type ${r[0]}.`;return null==t?e+=` Received ${t}`:"function"==typeof t&&t.name?e+=` Received function ${t.name}`:"object"==typeof t&&null!=t&&t.constructor?.name&&(e+=` Received an instance of ${t.constructor.name}`),e}const k=(e,...t)=>v("Key must be ",e,...t);function P(e,t,...r){return v(`Key for the ${e} algorithm must be `,t,...r)}const I=e=>!!c(e)||"KeyObject"===e?.[Symbol.toStringTag],R=["CryptoKey"];function C(e){if("object"!=typeof(t=e)||null===t||"[object Object]"!==Object.prototype.toString.call(e))return!1;var t;if(null===Object.getPrototypeOf(e))return!0;let r=e;for(;null!==Object.getPrototypeOf(r);)r=Object.getPrototypeOf(r);return Object.getPrototypeOf(e)===r}function x(e){return C(e)&&"string"==typeof e.kty}const T=e=>E(e);let D;const j=e=>"KeyObject"===e?.[Symbol.toStringTag],N=async(e,t,r,s,o=!1)=>{let n=e.get(t);if(n?.[s])return n[s];const a=await(async e=>{if(!e.alg)throw new TypeError('"alg" argument is required when "jwk.alg" is not present');const{algorithm:t,keyUsages:r}=function(e){let t,r;switch(e.kty){case"RSA":switch(e.alg){case"PS256":case"PS384":case"PS512":t={name:"RSA-PSS",hash:`SHA-${e.alg.slice(-3)}`},r=e.d?["sign"]:["verify"];break;case"RS256":case"RS384":case"RS512":t={name:"RSASSA-PKCS1-v1_5",hash:`SHA-${e.alg.slice(-3)}`},r=e.d?["sign"]:["verify"];break;case"RSA-OAEP":case"RSA-OAEP-256":case"RSA-OAEP-384":case"RSA-OAEP-512":t={name:"RSA-OAEP",hash:`SHA-${parseInt(e.alg.slice(-3),10)||1}`},r=e.d?["decrypt","unwrapKey"]:["encrypt","wrapKey"];break;default:throw new d('Invalid or unsupported JWK "alg" (Algorithm) Parameter value')}break;case"EC":switch(e.alg){case"ES256":t={name:"ECDSA",namedCurve:"P-256"},r=e.d?["sign"]:["verify"];break;case"ES384":t={name:"ECDSA",namedCurve:"P-384"},r=e.d?["sign"]:["verify"];break;case"ES512":t={name:"ECDSA",namedCurve:"P-521"},r=e.d?["sign"]:["verify"];break;case"ECDH-ES":case"ECDH-ES+A128KW":case"ECDH-ES+A192KW":case"ECDH-ES+A256KW":t={name:"ECDH",namedCurve:e.crv},r=e.d?["deriveBits"]:[];break;default:throw new d('Invalid or unsupported JWK "alg" (Algorithm) Parameter value')}break;case"OKP":switch(e.alg){case"Ed25519":t={name:"Ed25519"},r=e.d?["sign"]:["verify"];break;case"EdDSA":t={name:e.crv},r=e.d?["sign"]:["verify"];break;case"ECDH-ES":case"ECDH-ES+A128KW":case"ECDH-ES+A192KW":case"ECDH-ES+A256KW":t={name:e.crv},r=e.d?["deriveBits"]:[];break;default:throw new d('Invalid or unsupported JWK "alg" (Algorithm) Parameter value')}break;default:throw new d('Invalid or unsupported JWK "kty" (Key Type) Parameter value')}return{algorithm:t,keyUsages:r}}(e),s=[t,e.ext??!1,e.key_ops??r],o={...e};return delete o.alg,delete o.use,i.subtle.importKey("jwk",o,...s)})({...r,alg:s});return o&&Object.freeze(t),n?n[s]=a:e.set(t,{[s]:a}),a},H=async(e,t,r)=>{const s=await async function(e,t,r){if(t=await((e,t)=>{if(j(e)){let r=e.export({format:"jwk"});return r.k?T(r.k):(D||(D=new WeakMap),N(D,e,r,t))}return x(e)?e.k?E(e.k):(D||(D=new WeakMap),N(D,e,e,t,!0)):e})(t,e),c(t))return _(t,e,r),t;if(t instanceof Uint8Array){if(!e.startsWith("HS"))throw new TypeError(k(t,...R));return i.subtle.importKey("raw",t,{hash:`SHA-${e.slice(-3)}`,name:"HMAC"},!1,[r])}throw new TypeError(k(t,...R,"Uint8Array","JSON Web Key"))}(e,t,"sign");((e,t)=>{if(e.startsWith("RS")||e.startsWith("PS")){const{modulusLength:r}=t.algorithm;if("number"!=typeof r||r<2048)throw new TypeError(`${e} requires key modulusLength to be 2048 bits or larger`)}})(e,s);const o=await i.subtle.sign(function(e,t){const r=`SHA-${e.slice(-3)}`;switch(e){case"HS256":case"HS384":case"HS512":return{hash:r,name:"HMAC"};case"PS256":case"PS384":case"PS512":return{hash:r,name:"RSA-PSS",saltLength:e.slice(-3)>>3};case"RS256":case"RS384":case"RS512":return{hash:r,name:"RSASSA-PKCS1-v1_5"};case"ES256":case"ES384":case"ES512":return{hash:r,name:"ECDSA",namedCurve:t.namedCurve};case"Ed25519":return{name:"Ed25519"};case"EdDSA":return{name:t.name};default:throw new d(`alg ${e} is not supported either by JOSE or your javascript runtime`)}}(e,s.algorithm),s,r);return new Uint8Array(o)},K=e=>e?.[Symbol.toStringTag],O=(e,t,r)=>{if(void 0!==t.use&&"sig"!==t.use)throw new TypeError("Invalid key for this operation, when present its use must be sig");if(void 0!==t.key_ops&&!0!==t.key_ops.includes?.(r))throw new TypeError(`Invalid key for this operation, when present its key_ops must include ${r}`);if(void 0!==t.alg&&t.alg!==e)throw new TypeError(`Invalid key for this operation, when present its alg must be ${e}`);return!0};function $(e,t,r,s){t.startsWith("HS")||"dir"===t||t.startsWith("PBES2")||/^A\d{3}(?:GCM)?KW$/.test(t)?((e,t,r,s)=>{if(!(t instanceof Uint8Array)){if(s&&x(t)){if(function(e){return x(e)&&"oct"===e.kty&&"string"==typeof e.k}(t)&&O(e,t,r))return;throw new TypeError('JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present')}if(!I(t))throw new TypeError(P(e,t,...R,"Uint8Array",s?"JSON Web Key":null));if("secret"!==t.type)throw new TypeError(`${K(t)} instances for symmetric algorithms must be of type "secret"`)}})(t,r,s,e):((e,t,r,s)=>{if(s&&x(t))switch(r){case"sign":if(function(e){return"oct"!==e.kty&&"string"==typeof e.d}(t)&&O(e,t,r))return;throw new TypeError("JSON Web Key for this operation be a private JWK");case"verify":if(function(e){return"oct"!==e.kty&&void 0===e.d}(t)&&O(e,t,r))return;throw new TypeError("JSON Web Key for this operation be a public JWK")}if(!I(t))throw new TypeError(P(e,t,...R,s?"JSON Web Key":null));if("secret"===t.type)throw new TypeError(`${K(t)} instances for asymmetric algorithms must not be of type "secret"`);if("sign"===r&&"public"===t.type)throw new TypeError(`${K(t)} instances for asymmetric algorithm signing must be of type "private"`);if("decrypt"===r&&"public"===t.type)throw new TypeError(`${K(t)} instances for asymmetric algorithm decryption must be of type "private"`);if(t.algorithm&&"verify"===r&&"private"===t.type)throw new TypeError(`${K(t)} instances for asymmetric algorithm verifying must be of type "public"`);if(t.algorithm&&"encrypt"===r&&"private"===t.type)throw new TypeError(`${K(t)} instances for asymmetric algorithm encryption must be of type "public"`)})(t,r,s,e)}$.bind(void 0,!1);const W=$.bind(void 0,!0);class J{constructor(e){if(!(e instanceof Uint8Array))throw new TypeError("payload must be an instance of Uint8Array");this._payload=e}setProtectedHeader(e){if(this._protectedHeader)throw new TypeError("setProtectedHeader can only be called once");return this._protectedHeader=e,this}setUnprotectedHeader(e){if(this._unprotectedHeader)throw new TypeError("setUnprotectedHeader can only be called once");return this._unprotectedHeader=e,this}async sign(e,t){if(!this._protectedHeader&&!this._unprotectedHeader)throw new u("either setProtectedHeader or setUnprotectedHeader must be called before #sign()");if(!((...e)=>{const t=e.filter(Boolean);if(0===t.length||1===t.length)return!0;let r;for(const e of t){const t=Object.keys(e);if(r&&0!==r.size)for(const e of t){if(r.has(e))return!1;r.add(e)}else r=new Set(t)}return!0})(this._protectedHeader,this._unprotectedHeader))throw new u("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");const r={...this._protectedHeader,...this._unprotectedHeader};let s=!0;if(function(e,t,r,s,o){if(void 0!==o.crit&&void 0===s?.crit)throw new e('"crit" (Critical) Header Parameter MUST be integrity protected');if(!s||void 0===s.crit)return new Set;if(!Array.isArray(s.crit)||0===s.crit.length||s.crit.some(e=>"string"!=typeof e||0===e.length))throw new e('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');let n;n=void 0!==r?new Map([...Object.entries(r),...t.entries()]):t;for(const t of s.crit){if(!n.has(t))throw new d(`Extension Header Parameter "${t}" is not recognized`);if(void 0===o[t])throw new e(`Extension Header Parameter "${t}" is missing`);if(n.get(t)&&void 0===s[t])throw new e(`Extension Header Parameter "${t}" MUST be integrity protected`)}return new Set(s.crit)}(u,new Map([["b64",!0]]),t?.crit,this._protectedHeader,r).has("b64")&&(s=this._protectedHeader.b64,"boolean"!=typeof s))throw new u('The "b64" (base64url-encode payload) Header Parameter must be a boolean');const{alg:o}=r;if("string"!=typeof o||!o)throw new u('JWS "alg" (Algorithm) Header Parameter missing or invalid');W(o,e,"sign");let n,a=this._payload;s&&(a=f.encode(w(a))),n=this._protectedHeader?f.encode(w(JSON.stringify(this._protectedHeader))):f.encode("");const i=function(...e){const t=e.reduce((e,{length:t})=>e+t,0),r=new Uint8Array(t);let s=0;for(const t of e)r.set(t,s),s+=t.length;return r}(n,f.encode("."),a),c=await H(o,e,i),l={signature:w(c),payload:""};return s&&(l.payload=g.decode(a)),this._unprotectedHeader&&(l.header=this._unprotectedHeader),this._protectedHeader&&(l.protected=g.decode(n)),l}}class L{constructor(e){this._flattened=new J(e)}setProtectedHeader(e){return this._flattened.setProtectedHeader(e),this}async sign(e,t){const r=await this._flattened.sign(e,t);if(void 0===r.payload)throw new TypeError("use the flattened module for creating JWS with b64: false");return`${r.protected}.${r.payload}.${r.signature}`}}const M=e=>Math.floor(e.getTime()/1e3),V=/^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i,U=e=>{const t=V.exec(e);if(!t||t[4]&&t[1])throw new TypeError("Invalid time period format");const r=parseFloat(t[2]);let s;switch(t[3].toLowerCase()){case"sec":case"secs":case"second":case"seconds":case"s":s=Math.round(r);break;case"minute":case"minutes":case"min":case"mins":case"m":s=Math.round(60*r);break;case"hour":case"hours":case"hr":case"hrs":case"h":s=Math.round(3600*r);break;case"day":case"days":case"d":s=Math.round(86400*r);break;case"week":case"weeks":case"w":s=Math.round(604800*r);break;default:s=Math.round(31557600*r)}return"-"===t[1]||"ago"===t[4]?-s:s};function B(e,t){if(!Number.isFinite(t))throw new TypeError(`Invalid ${e} input`);return t}class F{constructor(e={}){if(!C(e))throw new TypeError("JWT Claims Set MUST be an object");this._payload=e}setIssuer(e){return this._payload={...this._payload,iss:e},this}setSubject(e){return this._payload={...this._payload,sub:e},this}setAudience(e){return this._payload={...this._payload,aud:e},this}setJti(e){return this._payload={...this._payload,jti:e},this}setNotBefore(e){return"number"==typeof e?this._payload={...this._payload,nbf:B("setNotBefore",e)}:e instanceof Date?this._payload={...this._payload,nbf:B("setNotBefore",M(e))}:this._payload={...this._payload,nbf:M(new Date)+U(e)},this}setExpirationTime(e){return"number"==typeof e?this._payload={...this._payload,exp:B("setExpirationTime",e)}:e instanceof Date?this._payload={...this._payload,exp:B("setExpirationTime",M(e))}:this._payload={...this._payload,exp:M(new Date)+U(e)},this}setIssuedAt(e){return void 0===e?this._payload={...this._payload,iat:M(new Date)}:e instanceof Date?this._payload={...this._payload,iat:B("setIssuedAt",M(e))}:this._payload="string"==typeof e?{...this._payload,iat:B("setIssuedAt",M(new Date)+U(e))}:{...this._payload,iat:B("setIssuedAt",e)},this}}class G extends F{setProtectedHeader(e){return this._protectedHeader=e,this}async sign(e,t){const r=new L(f.encode(JSON.stringify(this._payload)));if(r.setProtectedHeader(this._protectedHeader),Array.isArray(this._protectedHeader?.crit)&&this._protectedHeader.crit.includes("b64")&&!1===this._protectedHeader.b64)throw new h("JWTs MUST NOT use unencoded payload");return r.sign(e,t)}}async function q(e){if(e.accessToken)return e.accessToken;if(!e.serviceAccountKey)throw new Error("Either serviceAccountKey or accessToken must be provided");return await async function(e){const t=Math.floor(Date.now()/1e3);let r=e.private_key;if(!r)throw new Error("Private key is missing from service account key");if(r=r.trim(),r.includes("-----BEGIN")){if(r=r.replace(/\r\n/g,"\n").replace(/\r/g,"\n"),r.includes("BEGIN RSA PRIVATE KEY"))throw new Error("Private key is in PKCS#1 format (RSA PRIVATE KEY). Please download a new service account key from Google Cloud Console. The key should be in PKCS#8 format (PRIVATE KEY).");const e=r.match(/-----BEGIN PRIVATE KEY-----\n?([\s\S]*?)\n?-----END PRIVATE KEY-----/);if(e){const t=e[1].replace(/\s/g,"");(!t.includes("\n")||t.length>64)&&(r=`-----BEGIN PRIVATE KEY-----\n${t.match(/.{1,64}/g)?.join("\n")||t}\n-----END PRIVATE KEY-----`)}}else{const e=r.replace(/\s/g,"");r=`-----BEGIN PRIVATE KEY-----\n${e.match(/.{1,64}/g)?.join("\n")||e}\n-----END PRIVATE KEY-----`}try{const s=await y(r,"RS256"),o=await new G({scope:"https://www.googleapis.com/auth/cloud-platform"}).setProtectedHeader({alg:"RS256"}).setIssuedAt(t).setExpirationTime(t+3600).setIssuer(e.client_email).setSubject(e.client_email).setAudience("https://oauth2.googleapis.com/token").sign(s),n=await fetch("https://oauth2.googleapis.com/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"urn:ietf:params:oauth:grant-type:jwt-bearer",assertion:o})});if(!n.ok){const e=await n.json();throw new Error(e.error_description||"Failed to get access token")}return(await n.json()).access_token}catch(e){if(e.message&&e.message.includes("pkcs8"))throw new Error("Invalid private key format. The service account key must be in PKCS#8 format. Please ensure your service account key JSON file has a properly formatted private_key field. If you downloaded the key from Google Cloud Console, it should already be in the correct format.");throw e}}(e.serviceAccountKey)}function Y(e,t,r,s){return`projects/${e}/locations/${t}/agents/${r}/sessions/${s}`}function z(e){let t=null;for(const r of e)if(r.payload){if(r.payload.richContent){t=r.payload.richContent;break}if(r.payload.fields&&r.payload.fields.richContent){const e=r.payload.fields.richContent;e.listValue&&e.listValue.values?t=e.listValue.values.map(e=>e.listValue&&e.listValue.values?e.listValue.values.map(e=>{if(e.structValue&&e.structValue.fields){const t=e.structValue.fields;if(t.type&&t.options)return{type:t.type.stringValue||t.type,options:t.options.listValue?t.options.listValue.values.map(e=>({text:e.structValue?.fields?.text?.stringValue||"",payload:e.structValue?.fields?.payload?.stringValue||""})):[]}}return e}):e):"object"!=typeof e||e.listValue||(t=e);break}}return t}const X=function({title:e="💬 BlockSpark AI Assistant",subtitle:t="We're here to help",welcomeTitle:r="👋 Welcome to Blockspark",welcomeMessage:s="My name is BlockSpark AI Assistant and I'll guide you.",welcomeCta:o="💬 Click here to start chatting!",showWelcomePopup:i=!0,welcomePopupDelay:c=1500,fallbackWelcomeMessage:l="Hello! I'm BlockSpark AI Assistant. How can I help you today?",inputPlaceholder:d="Type your message...",emptyStateMessage:u="Hi! I'm BlockSpark AI Assistant. How can I help you today?",debug:h=!1,dfProjectId:p,dfLocation:m="us-central1",dfAgentId:y,serviceAccountKey:f,accessToken:g,languageCode:w="en"}){const[E,S]=(0,a.useState)(!1),[b,A]=(0,a.useState)(!1),[_,v]=(0,a.useState)([]),[k,P]=(0,a.useState)(""),[I,R]=(0,a.useState)(!1),[C,x]=(0,a.useState)(null),[T,D]=(0,a.useState)(!1),j=(0,a.useRef)(null),N=()=>{if(p&&y)return{dfProjectId:p,dfLocation:m||"us-central1",dfAgentId:y,serviceAccountKey:f,accessToken:g,languageCode:w||"en"}};(0,a.useEffect)(()=>{if(!i)return;const e=setTimeout(()=>{A(!0)},c);return()=>clearTimeout(e)},[i,c]),(0,a.useEffect)(()=>{j.current?.scrollIntoView({behavior:"smooth"})},[_]);const H=async()=>{if(C)return C;try{D(!0);const e=N();if(!e)throw new Error("Dialogflow configuration is missing. Please provide dfProjectId, dfAgentId, and either serviceAccountKey or accessToken.");const t=await async function(e){try{const t=await q(e),r=`session_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,s=e.dfLocation.split(" ")[0].trim(),o=`https://${s}-dialogflow.googleapis.com/v3/${Y(e.dfProjectId,s,e.dfAgentId,r)}:detectIntent`,n={queryInput:{text:{text:"hello"},languageCode:e.languageCode||"en"}},a=await fetch(o,{method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},body:JSON.stringify(n)});if(!a.ok){const e=await a.json().catch(()=>({}));throw new Error(e.error?.message||`HTTP error! status: ${a.status}`)}const i=await a.json();let c="Hello! I'm BlockSpark AI Assistant. How can I help you today?",l=null;if(i.queryResult?.responseMessages){const e=i.queryResult.responseMessages.filter(e=>e.text).map(e=>e.text.text.join(" "));e.length>0&&(c=e.join(" ")),l=z(i.queryResult.responseMessages)}else i.queryResult?.fulfillmentText&&(c=i.queryResult.fulfillmentText);return{session_id:r,message:c,...l&&{richContent:l}}}catch(e){console.error("Error creating Dialogflow session:",e);const t=e.message||"Failed to create session";if(t.includes("401")||t.includes("Unauthorized"))throw new Error("Authentication failed. Please check your service account key or access token.");if(t.includes("403")||t.includes("Forbidden"))throw new Error("Access forbidden. Please check your Dialogflow API permissions.");if(t.includes("404")||t.includes("Not Found"))throw new Error("Dialogflow agent not found. Please check your project ID, location, and agent ID.");throw new Error(t)}}(e);if(x(t.session_id),t.message){h&&(console.log("Session response richContent:",t.richContent),console.log("Full session response:",t));const e={id:`welcome-${Date.now()}`,text:t.message,sender:"bot",timestamp:new Date,richContent:t.richContent};v([e])}return t.session_id}catch(e){console.error("Error creating session:",e),h&&console.error("Full error details:",{message:e.message,stack:e.stack,config:N()});const t={id:`error-${Date.now()}`,text:h?`Error: ${e.message||"Failed to create session. Please check your Dialogflow configuration."}`:l,sender:"bot",timestamp:new Date};return v([t]),null}finally{D(!1)}},K=async(e,t,r=!1)=>{if(!e.trim())return;let s=C;if(!s)try{if(s=await H(),!s){const e={id:Date.now().toString(),text:h?"Failed to create session. Please check the console for details.":"Sorry, I'm having trouble connecting. Please try again.",sender:"bot",timestamp:new Date};return void v(t=>[...t,e])}}catch(e){console.error("Error in createSession:",e);const t={id:Date.now().toString(),text:h?`Connection Error: ${e.message||"Please check your Dialogflow configuration."}`:"Sorry, I'm having trouble connecting. Please check your configuration.",sender:"bot",timestamp:new Date};return void v(e=>[...e,t])}if(!r){const r={id:Date.now().toString(),text:t||e.trim(),sender:"user",timestamp:new Date};v(e=>[...e,r])}P(""),R(!0);try{const t=N();if(!t)throw new Error("Dialogflow configuration is missing. Please provide dfProjectId, dfAgentId, and either serviceAccountKey or accessToken.");const r=await async function(e,t,r){try{const s=await q(r),o=r.dfLocation.split(" ")[0].trim(),n=`https://${o}-dialogflow.googleapis.com/v3/${Y(r.dfProjectId,o,r.dfAgentId,t)}:detectIntent`,a={queryInput:{text:{text:e.trim()},languageCode:r.languageCode||"en"}},i=await fetch(n,{method:"POST",headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json"},body:JSON.stringify(a)});if(!i.ok){const e=await i.text();let t={};try{t=JSON.parse(e)}catch{t={message:e||`HTTP ${i.status}`}}const r=t.error?.message||t.message||`HTTP error! status: ${i.status}`;throw console.error("Dialogflow API Error (sendMessage):",{status:i.status,statusText:i.statusText,error:t,endpoint:n}),new Error(r)}const c=await i.json();let l="I'm sorry, I didn't understand that. Could you please rephrase?",d=null;if(c.queryResult?.responseMessages){const e=c.queryResult.responseMessages.filter(e=>e.text).map(e=>e.text.text.join(" "));e.length>0&&(l=e.join(" ")),d=z(c.queryResult.responseMessages)}else c.queryResult?.fulfillmentText&&(l=c.queryResult.fulfillmentText);return{response:l,session_id:t,source:"dialogflow",timestamp:(new Date).toISOString(),...d&&{richContent:d}}}catch(e){console.error("Error sending message to Dialogflow:",e);const t=e.message||"Failed to send message";if(t.includes("401")||t.includes("Unauthorized"))throw new Error("Authentication failed. Please check your service account key or access token.");if(t.includes("403")||t.includes("Forbidden"))throw new Error("Access forbidden. Please check your Dialogflow API permissions.");if(t.includes("404")||t.includes("Not Found"))throw new Error("Dialogflow agent not found. Please check your project ID, location, and agent ID.");if(t.includes("CORS"))throw new Error("CORS error. Dialogflow API may not allow browser requests. Consider using a backend proxy.");throw new Error(t)}}(e.trim(),s,t);h&&(console.log("Chat response richContent:",r.richContent),console.log("Full chat response:",r));const o={id:(Date.now()+1).toString(),text:r.response,sender:"bot",timestamp:new Date(r.timestamp||Date.now()),richContent:r.richContent};v(e=>[...e,o])}catch(e){console.error("Error sending message:",e),h&&console.error("Full error details:",{message:e.message,stack:e.stack,sessionId:s,config:N()});const t={id:(Date.now()+1).toString(),text:h?`Error: ${e.message||"Failed to send message. Please check your Dialogflow configuration."}`:e.message?.includes("Failed to fetch")||e.message?.includes("CORS")?"Unable to connect to Dialogflow. Please check your configuration and network.":"Sorry, I'm having trouble processing your message. Please try again.",sender:"bot",timestamp:new Date};v(e=>[...e,t])}finally{R(!1)}},O=async()=>{S(!0),A(!1),C||await H()};return(0,n.jsxs)(n.Fragment,{children:[b&&!E&&(0,n.jsxs)("div",{className:"custom-welcome-popup",onClick:O,children:[(0,n.jsxs)("div",{className:"custom-welcome-header",children:[(0,n.jsx)("div",{className:"custom-welcome-title",children:r}),(0,n.jsx)("button",{className:"custom-close-popup",onClick:e=>{e.stopPropagation(),A(!1)},children:"×"})]}),(0,n.jsx)("div",{className:"custom-welcome-message",children:s}),(0,n.jsx)("div",{className:"custom-welcome-cta",children:o})]}),!E&&(0,n.jsx)("button",{className:"custom-chat-toggle-btn",onClick:O,"aria-label":"Open chat",children:(0,n.jsx)("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:(0,n.jsx)("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})}),E&&(0,n.jsxs)("div",{className:"custom-chat-window",children:[(0,n.jsxs)("div",{className:"custom-chat-header",children:[(0,n.jsxs)("div",{className:"custom-chat-header-content",children:[(0,n.jsx)("div",{className:"custom-chat-title",children:e}),(0,n.jsx)("div",{className:"custom-chat-subtitle",children:t})]}),(0,n.jsx)("button",{className:"custom-chat-close-btn",onClick:()=>{S(!1)},"aria-label":"Close chat",children:"×"})]}),(0,n.jsxs)("div",{className:"custom-chat-messages",children:[T&&0===_.length&&(0,n.jsxs)("div",{className:"custom-chat-empty",children:[(0,n.jsxs)("div",{className:"custom-typing-indicator",children:[(0,n.jsx)("span",{}),(0,n.jsx)("span",{}),(0,n.jsx)("span",{})]}),(0,n.jsx)("p",{children:"Initializing chat..."})]}),!T&&0===_.length&&(0,n.jsxs)("div",{className:"custom-chat-empty",children:[(0,n.jsx)("div",{className:"custom-chat-empty-icon",children:"👋"}),(0,n.jsx)("p",{children:u})]}),_.map(e=>(0,n.jsxs)("div",{className:`custom-message custom-message-${e.sender}`,children:[(0,n.jsx)("div",{className:"custom-message-content",children:e.text}),(h&&e.richContent&&(console.log("Rendering message with richContent:",e.richContent),console.log("richContent type:",typeof e.richContent),console.log("richContent is array:",Array.isArray(e.richContent)),console.log("richContent length:",e.richContent?.length)),e.richContent&&Array.isArray(e.richContent)&&e.richContent.length>0?(0,n.jsx)("div",{className:"custom-chips-container",children:e.richContent.map((e,t)=>{if(h&&console.log(`Processing contentGroup ${t}:`,e),!Array.isArray(e)){const r=e;return r&&"chips"===r.type&&r.options?(0,n.jsx)("div",{className:"custom-chips-group",children:r.options.map((e,t)=>(0,n.jsx)("button",{className:"custom-chip-button",onClick:()=>{const t={id:Date.now().toString(),text:e.text,sender:"user",timestamp:new Date};v(e=>[...e,t]),K(e.text,e.text,!0)},type:"button",children:e.text},t))},t):null}return e.map((e,r)=>(h&&console.log(`Processing content ${t}-${r}:`,e),e&&"chips"===e.type&&e.options?(0,n.jsx)("div",{className:"custom-chips-group",children:e.options.map((e,t)=>(0,n.jsx)("button",{className:"custom-chip-button",onClick:()=>{const t={id:Date.now().toString(),text:e.text,sender:"user",timestamp:new Date};v(e=>[...e,t]),K(e.text,e.text,!0)},type:"button",children:e.text},t))},`${t}-${r}`):null))})}):null),(0,n.jsx)("div",{className:"custom-message-time",children:e.timestamp.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})})]},e.id)),I&&(0,n.jsx)("div",{className:"custom-message custom-message-bot",children:(0,n.jsxs)("div",{className:"custom-typing-indicator",children:[(0,n.jsx)("span",{}),(0,n.jsx)("span",{}),(0,n.jsx)("span",{})]})}),(0,n.jsx)("div",{ref:j})]}),(0,n.jsxs)("form",{className:"custom-chat-input-form",onSubmit:e=>{e.preventDefault(),K(k)},children:[(0,n.jsx)("input",{type:"text",className:"custom-chat-input",value:k,onChange:e=>P(e.target.value),placeholder:d,disabled:I||T}),(0,n.jsx)("button",{type:"submit",className:"custom-chat-send-btn",disabled:!k.trim()||I||T,children:(0,n.jsxs)("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,n.jsx)("line",{x1:"22",y1:"2",x2:"11",y2:"13"}),(0,n.jsx)("polygon",{points:"22 2 15 22 11 13 2 9 22 2"})]})})]})]})]})};return o.default})());
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface DialogflowConfig {
|
|
2
|
+
dfProjectId: string;
|
|
3
|
+
dfLocation: string;
|
|
4
|
+
dfAgentId: string;
|
|
5
|
+
serviceAccountKey?: any;
|
|
6
|
+
accessToken?: string;
|
|
7
|
+
languageCode?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SessionResponse {
|
|
10
|
+
session_id: string;
|
|
11
|
+
message: string;
|
|
12
|
+
richContent?: any;
|
|
13
|
+
}
|
|
14
|
+
export interface ChatResponse {
|
|
15
|
+
response: string;
|
|
16
|
+
session_id: string;
|
|
17
|
+
source: string;
|
|
18
|
+
timestamp: string;
|
|
19
|
+
richContent?: any;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create a new Dialogflow session
|
|
23
|
+
* @param config - Dialogflow configuration
|
|
24
|
+
* @returns Promise with session ID and welcome message
|
|
25
|
+
*/
|
|
26
|
+
export declare function createDialogflowSession(config: DialogflowConfig): Promise<SessionResponse>;
|
|
27
|
+
/**
|
|
28
|
+
* Send a message to Dialogflow
|
|
29
|
+
* @param message - The user's message
|
|
30
|
+
* @param sessionId - The session ID
|
|
31
|
+
* @param config - Dialogflow configuration
|
|
32
|
+
* @returns Promise with bot response
|
|
33
|
+
*/
|
|
34
|
+
export declare function sendDialogflowMessage(message: string, sessionId: string, config: DialogflowConfig): Promise<ChatResponse>;
|
|
35
|
+
//# sourceMappingURL=dialogflowClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialogflowClient.d.ts","sourceRoot":"","sources":["../../src/services/dialogflowClient.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,GAAG,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,GAAG,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,GAAG,CAAC;CACnB;AAiKD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CA0EhG;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,YAAY,CAAC,CAyFvB"}
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
/* ========================================
|
|
2
|
+
Custom Chat Widget Styles
|
|
3
|
+
======================================== */
|
|
4
|
+
|
|
5
|
+
/* Welcome Popup */
|
|
6
|
+
.custom-welcome-popup {
|
|
7
|
+
position: fixed;
|
|
8
|
+
bottom: 20px;
|
|
9
|
+
right: 90px;
|
|
10
|
+
background: linear-gradient(135deg, #2d7a4f 0%, #1f5937 100%);
|
|
11
|
+
color: white;
|
|
12
|
+
padding: 20px;
|
|
13
|
+
border-radius: 12px;
|
|
14
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
|
|
15
|
+
max-width: 350px;
|
|
16
|
+
z-index: 99998;
|
|
17
|
+
animation: customSlideIn 0.4s ease-out;
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
transition: transform 0.2s;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.custom-welcome-popup:hover {
|
|
23
|
+
transform: translateY(-2px);
|
|
24
|
+
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.2);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@keyframes customSlideIn {
|
|
28
|
+
from {
|
|
29
|
+
transform: translateY(20px);
|
|
30
|
+
opacity: 0;
|
|
31
|
+
}
|
|
32
|
+
to {
|
|
33
|
+
transform: translateY(0);
|
|
34
|
+
opacity: 1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.custom-welcome-header {
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: flex-start;
|
|
41
|
+
justify-content: space-between;
|
|
42
|
+
margin-bottom: 12px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.custom-welcome-title {
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
gap: 8px;
|
|
49
|
+
font-size: 16px;
|
|
50
|
+
font-weight: 600;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.custom-close-popup {
|
|
54
|
+
background: none;
|
|
55
|
+
border: none;
|
|
56
|
+
color: white;
|
|
57
|
+
font-size: 24px;
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
padding: 0;
|
|
60
|
+
width: 24px;
|
|
61
|
+
height: 24px;
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
justify-content: center;
|
|
65
|
+
opacity: 0.8;
|
|
66
|
+
transition: opacity 0.2s;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.custom-close-popup:hover {
|
|
70
|
+
opacity: 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.custom-welcome-message {
|
|
74
|
+
font-size: 14px;
|
|
75
|
+
line-height: 1.5;
|
|
76
|
+
margin-bottom: 10px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.custom-welcome-cta {
|
|
80
|
+
font-size: 13px;
|
|
81
|
+
opacity: 0.9;
|
|
82
|
+
font-style: italic;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* Chat Toggle Button */
|
|
86
|
+
.custom-chat-toggle-btn {
|
|
87
|
+
position: fixed;
|
|
88
|
+
bottom: 20px;
|
|
89
|
+
right: 20px;
|
|
90
|
+
width: 60px;
|
|
91
|
+
height: 60px;
|
|
92
|
+
border-radius: 50%;
|
|
93
|
+
background: linear-gradient(135deg, #2d7a4f 0%, #1f5937 100%);
|
|
94
|
+
color: white;
|
|
95
|
+
border: none;
|
|
96
|
+
cursor: pointer;
|
|
97
|
+
display: flex;
|
|
98
|
+
align-items: center;
|
|
99
|
+
justify-content: center;
|
|
100
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
101
|
+
z-index: 99999;
|
|
102
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.custom-chat-toggle-btn:hover {
|
|
106
|
+
transform: scale(1.1);
|
|
107
|
+
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.custom-chat-toggle-btn:active {
|
|
111
|
+
transform: scale(0.95);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Chat Window */
|
|
115
|
+
.custom-chat-window {
|
|
116
|
+
position: fixed;
|
|
117
|
+
bottom: 20px;
|
|
118
|
+
right: 20px;
|
|
119
|
+
width: 380px;
|
|
120
|
+
height: 600px;
|
|
121
|
+
max-height: calc(100vh - 40px);
|
|
122
|
+
background: white;
|
|
123
|
+
border-radius: 16px;
|
|
124
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
|
|
125
|
+
display: flex;
|
|
126
|
+
flex-direction: column;
|
|
127
|
+
z-index: 99999;
|
|
128
|
+
animation: customChatSlideUp 0.3s ease-out;
|
|
129
|
+
overflow: hidden;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@keyframes customChatSlideUp {
|
|
133
|
+
from {
|
|
134
|
+
transform: translateY(20px);
|
|
135
|
+
opacity: 0;
|
|
136
|
+
}
|
|
137
|
+
to {
|
|
138
|
+
transform: translateY(0);
|
|
139
|
+
opacity: 1;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Chat Header */
|
|
144
|
+
.custom-chat-header {
|
|
145
|
+
background: linear-gradient(135deg, #2d7a4f 0%, #1f5937 100%);
|
|
146
|
+
color: white;
|
|
147
|
+
padding: 20px;
|
|
148
|
+
display: flex;
|
|
149
|
+
justify-content: space-between;
|
|
150
|
+
align-items: flex-start;
|
|
151
|
+
flex-shrink: 0;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.custom-chat-header-content {
|
|
155
|
+
flex: 1;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.custom-chat-title {
|
|
159
|
+
font-size: 18px;
|
|
160
|
+
font-weight: 600;
|
|
161
|
+
margin-bottom: 4px;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.custom-chat-subtitle {
|
|
165
|
+
font-size: 12px;
|
|
166
|
+
opacity: 0.9;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.custom-chat-close-btn {
|
|
170
|
+
background: none;
|
|
171
|
+
border: none;
|
|
172
|
+
color: white;
|
|
173
|
+
font-size: 28px;
|
|
174
|
+
cursor: pointer;
|
|
175
|
+
padding: 0;
|
|
176
|
+
width: 32px;
|
|
177
|
+
height: 32px;
|
|
178
|
+
display: flex;
|
|
179
|
+
align-items: center;
|
|
180
|
+
justify-content: center;
|
|
181
|
+
opacity: 0.8;
|
|
182
|
+
transition: opacity 0.2s;
|
|
183
|
+
line-height: 1;
|
|
184
|
+
border-radius: 50%;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.custom-chat-close-btn:hover {
|
|
188
|
+
opacity: 1;
|
|
189
|
+
background: rgba(255, 255, 255, 0.1);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* Chat Messages Area */
|
|
193
|
+
.custom-chat-messages {
|
|
194
|
+
flex: 1;
|
|
195
|
+
overflow-y: auto;
|
|
196
|
+
padding: 20px;
|
|
197
|
+
display: flex;
|
|
198
|
+
flex-direction: column;
|
|
199
|
+
gap: 12px;
|
|
200
|
+
background: #f8f9fa;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.custom-chat-messages::-webkit-scrollbar {
|
|
204
|
+
width: 6px;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.custom-chat-messages::-webkit-scrollbar-track {
|
|
208
|
+
background: transparent;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.custom-chat-messages::-webkit-scrollbar-thumb {
|
|
212
|
+
background: #ddd;
|
|
213
|
+
border-radius: 3px;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.custom-chat-messages::-webkit-scrollbar-thumb:hover {
|
|
217
|
+
background: #bbb;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.custom-chat-empty {
|
|
221
|
+
display: flex;
|
|
222
|
+
flex-direction: column;
|
|
223
|
+
align-items: center;
|
|
224
|
+
justify-content: center;
|
|
225
|
+
height: 100%;
|
|
226
|
+
text-align: center;
|
|
227
|
+
color: #666;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.custom-chat-empty-icon {
|
|
231
|
+
font-size: 48px;
|
|
232
|
+
margin-bottom: 12px;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.custom-chat-empty p {
|
|
236
|
+
font-size: 16px;
|
|
237
|
+
line-height: 1.5;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/* Messages */
|
|
241
|
+
.custom-message {
|
|
242
|
+
display: flex;
|
|
243
|
+
flex-direction: column;
|
|
244
|
+
max-width: 75%;
|
|
245
|
+
animation: customMessageFadeIn 0.3s ease-out;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
@keyframes customMessageFadeIn {
|
|
249
|
+
from {
|
|
250
|
+
opacity: 0;
|
|
251
|
+
transform: translateY(10px);
|
|
252
|
+
}
|
|
253
|
+
to {
|
|
254
|
+
opacity: 1;
|
|
255
|
+
transform: translateY(0);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.custom-message-user {
|
|
260
|
+
align-self: flex-end;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.custom-message-bot {
|
|
264
|
+
align-self: flex-start;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.custom-message-content {
|
|
268
|
+
padding: 12px 16px;
|
|
269
|
+
border-radius: 16px;
|
|
270
|
+
word-wrap: break-word;
|
|
271
|
+
line-height: 1.5;
|
|
272
|
+
font-size: 14px;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.custom-message-user .custom-message-content {
|
|
276
|
+
background: linear-gradient(135deg, #2d7a4f 0%, #1f5937 100%);
|
|
277
|
+
color: white;
|
|
278
|
+
border-bottom-right-radius: 4px;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.custom-message-bot .custom-message-content {
|
|
282
|
+
background: white;
|
|
283
|
+
color: #333;
|
|
284
|
+
border-bottom-left-radius: 4px;
|
|
285
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.custom-message-time {
|
|
289
|
+
font-size: 10px;
|
|
290
|
+
color: #999;
|
|
291
|
+
margin-top: 4px;
|
|
292
|
+
padding: 0 4px;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* Chip Buttons */
|
|
296
|
+
.custom-chips-container {
|
|
297
|
+
margin-top: 12px;
|
|
298
|
+
display: flex;
|
|
299
|
+
flex-direction: column;
|
|
300
|
+
gap: 8px;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.custom-chips-group {
|
|
304
|
+
display: flex;
|
|
305
|
+
flex-wrap: wrap;
|
|
306
|
+
gap: 8px;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.custom-chip-button {
|
|
310
|
+
background: white;
|
|
311
|
+
border: 1.5px solid #2d7a4f;
|
|
312
|
+
color: #2d7a4f;
|
|
313
|
+
padding: 8px 16px;
|
|
314
|
+
border-radius: 20px;
|
|
315
|
+
font-size: 13px;
|
|
316
|
+
font-weight: 500;
|
|
317
|
+
cursor: pointer;
|
|
318
|
+
transition: all 0.2s ease;
|
|
319
|
+
white-space: nowrap;
|
|
320
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.custom-chip-button:hover {
|
|
324
|
+
background: linear-gradient(135deg, #2d7a4f 0%, #1f5937 100%);
|
|
325
|
+
color: white;
|
|
326
|
+
transform: translateY(-1px);
|
|
327
|
+
box-shadow: 0 2px 6px rgba(45, 122, 79, 0.3);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.custom-chip-button:active {
|
|
331
|
+
transform: translateY(0);
|
|
332
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/* Typing Indicator */
|
|
336
|
+
.custom-typing-indicator {
|
|
337
|
+
display: flex;
|
|
338
|
+
gap: 4px;
|
|
339
|
+
padding: 12px 16px;
|
|
340
|
+
background: white;
|
|
341
|
+
border-radius: 16px;
|
|
342
|
+
border-bottom-left-radius: 4px;
|
|
343
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
344
|
+
width: fit-content;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.custom-typing-indicator span {
|
|
348
|
+
width: 8px;
|
|
349
|
+
height: 8px;
|
|
350
|
+
border-radius: 50%;
|
|
351
|
+
background: #999;
|
|
352
|
+
animation: customTypingBounce 1.4s infinite ease-in-out;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.custom-typing-indicator span:nth-child(1) {
|
|
356
|
+
animation-delay: -0.32s;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.custom-typing-indicator span:nth-child(2) {
|
|
360
|
+
animation-delay: -0.16s;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
@keyframes customTypingBounce {
|
|
364
|
+
0%,
|
|
365
|
+
80%,
|
|
366
|
+
100% {
|
|
367
|
+
transform: scale(0.8);
|
|
368
|
+
opacity: 0.5;
|
|
369
|
+
}
|
|
370
|
+
40% {
|
|
371
|
+
transform: scale(1);
|
|
372
|
+
opacity: 1;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/* Chat Input Form */
|
|
377
|
+
.custom-chat-input-form {
|
|
378
|
+
display: flex;
|
|
379
|
+
padding: 16px;
|
|
380
|
+
background: white;
|
|
381
|
+
border-top: 1px solid #e0e0e0;
|
|
382
|
+
gap: 8px;
|
|
383
|
+
flex-shrink: 0;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.custom-chat-input {
|
|
387
|
+
flex: 1;
|
|
388
|
+
padding: 12px 16px;
|
|
389
|
+
border: 1px solid #e0e0e0;
|
|
390
|
+
border-radius: 24px;
|
|
391
|
+
outline: none;
|
|
392
|
+
font-size: 14px;
|
|
393
|
+
transition: border-color 0.2s;
|
|
394
|
+
font-family: inherit;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.custom-chat-input:focus {
|
|
398
|
+
border-color: #2d7a4f;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.custom-chat-input:disabled {
|
|
402
|
+
background: #f5f5f5;
|
|
403
|
+
cursor: not-allowed;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.custom-chat-send-btn {
|
|
407
|
+
width: 44px;
|
|
408
|
+
height: 44px;
|
|
409
|
+
border-radius: 50%;
|
|
410
|
+
background: linear-gradient(135deg, #2d7a4f 0%, #1f5937 100%);
|
|
411
|
+
color: white;
|
|
412
|
+
border: none;
|
|
413
|
+
cursor: pointer;
|
|
414
|
+
display: flex;
|
|
415
|
+
align-items: center;
|
|
416
|
+
justify-content: center;
|
|
417
|
+
transition: transform 0.2s, opacity 0.2s;
|
|
418
|
+
flex-shrink: 0;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.custom-chat-send-btn:hover:not(:disabled) {
|
|
422
|
+
transform: scale(1.05);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.custom-chat-send-btn:active:not(:disabled) {
|
|
426
|
+
transform: scale(0.95);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.custom-chat-send-btn:disabled {
|
|
430
|
+
opacity: 0.5;
|
|
431
|
+
cursor: not-allowed;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/* Responsive Design */
|
|
435
|
+
@media (max-width: 480px) {
|
|
436
|
+
.custom-welcome-popup {
|
|
437
|
+
right: 10px;
|
|
438
|
+
left: 10px;
|
|
439
|
+
bottom: 90px;
|
|
440
|
+
max-width: none;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.custom-chat-window {
|
|
444
|
+
width: calc(100vw - 20px);
|
|
445
|
+
height: calc(100vh - 20px);
|
|
446
|
+
bottom: 10px;
|
|
447
|
+
right: 10px;
|
|
448
|
+
border-radius: 12px;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
.custom-chat-toggle-btn {
|
|
452
|
+
bottom: 10px;
|
|
453
|
+
right: 10px;
|
|
454
|
+
width: 56px;
|
|
455
|
+
height: 56px;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.custom-message {
|
|
459
|
+
max-width: 85%;
|
|
460
|
+
}
|
|
461
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,YAAY,GACb,MAAM,6BAA6B,CAAC;AAGrC,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@blockspark/chat-widget",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "BlockSpark AI Chat Widget - A reusable React chat component",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "webpack --mode production",
|
|
14
|
+
"dev": "webpack --mode development --watch",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
|
19
|
+
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"jose": "^5.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/react": "^18.3.5",
|
|
26
|
+
"@types/react-dom": "^18.3.0",
|
|
27
|
+
"typescript": "^5.6.2",
|
|
28
|
+
"webpack": "^5.94.0",
|
|
29
|
+
"webpack-cli": "^5.1.4",
|
|
30
|
+
"ts-loader": "^9.5.1",
|
|
31
|
+
"css-loader": "^7.1.2",
|
|
32
|
+
"style-loader": "^4.0.0",
|
|
33
|
+
"mini-css-extract-plugin": "^2.9.0"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"chat",
|
|
37
|
+
"widget",
|
|
38
|
+
"react",
|
|
39
|
+
"dialogflow",
|
|
40
|
+
"ai",
|
|
41
|
+
"chatbot"
|
|
42
|
+
],
|
|
43
|
+
"author": "",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
}
|
|
48
|
+
}
|