@eka-care/medassist-widget-embed 0.2.4 → 0.2.5
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/dist/iframe.js +83 -11
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +57 -7
- package/dist/src/medassist-widget.css +795 -277
- package/dist/src/medassist-widget.js +1074 -458
- package/dist/src/medassist-widget.js.map +1 -1
- package/iframe.ts +110 -10
- package/index.ts +69 -6
- package/package.json +1 -1
- package/src/medassist-widget.css +795 -277
- package/src/medassist-widget.js +1074 -458
- package/src/medassist-widget.js.map +1 -1
- package/test.html +8 -8
package/iframe.ts
CHANGED
|
@@ -29,6 +29,77 @@
|
|
|
29
29
|
return undefined;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
+
/** Theme from agent-config API (has mode; textColor derived: dark → black, light → white) */
|
|
33
|
+
type AgentConfig = {
|
|
34
|
+
name?: string;
|
|
35
|
+
theme?: {
|
|
36
|
+
background?: string;
|
|
37
|
+
background_img?: string;
|
|
38
|
+
accent?: string;
|
|
39
|
+
mode?: "light" | "dark";
|
|
40
|
+
title_img?: string;
|
|
41
|
+
icon_img?: string;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
type WidgetTheme = {
|
|
46
|
+
background?: string;
|
|
47
|
+
backgroundImage?: string;
|
|
48
|
+
primary?: string;
|
|
49
|
+
textColor?: "black" | "white";
|
|
50
|
+
titleImg?: string;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const API_FETCH_TIMEOUT_MS = 10000;
|
|
54
|
+
|
|
55
|
+
/** Map agent-config API theme to widget theme (mode → textColor: dark→black, light→white) */
|
|
56
|
+
function mapAgentConfigThemeToWidgetTheme(
|
|
57
|
+
apiTheme: AgentConfig["theme"] | undefined
|
|
58
|
+
): WidgetTheme | undefined {
|
|
59
|
+
if (!apiTheme) return undefined;
|
|
60
|
+
const textColor =
|
|
61
|
+
apiTheme.mode === "dark"
|
|
62
|
+
? "white"
|
|
63
|
+
: apiTheme.mode === "light"
|
|
64
|
+
? "black"
|
|
65
|
+
: undefined;
|
|
66
|
+
return {
|
|
67
|
+
...(apiTheme.background && { background: apiTheme.background }),
|
|
68
|
+
...(apiTheme.background_img && {
|
|
69
|
+
backgroundImage: apiTheme.background_img,
|
|
70
|
+
}),
|
|
71
|
+
...(apiTheme.accent && { primary: apiTheme.accent }),
|
|
72
|
+
...(textColor && { textColor }),
|
|
73
|
+
...(apiTheme.title_img && { titleImg: apiTheme.title_img }),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Fetch agent-config from API with timeout; aborts if pending > 10s */
|
|
78
|
+
async function fetchAgentConfig(
|
|
79
|
+
baseUrl: string,
|
|
80
|
+
agentId: string
|
|
81
|
+
): Promise<AgentConfig | undefined> {
|
|
82
|
+
const url = `${baseUrl.replace(/\/$/, "")}/med-assist/agent-config/${agentId}`;
|
|
83
|
+
const controller = new AbortController();
|
|
84
|
+
const timeoutId = setTimeout(() => controller.abort(), API_FETCH_TIMEOUT_MS);
|
|
85
|
+
try {
|
|
86
|
+
const res = await fetch(url, {
|
|
87
|
+
signal: controller.signal,
|
|
88
|
+
headers: {
|
|
89
|
+
"ngrok-skip-browser-warning": "69420",
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
if (!res.ok) return undefined;
|
|
93
|
+
const json = await res.json();
|
|
94
|
+
if (json?.success && json?.data?.theme) return json.data as AgentConfig;
|
|
95
|
+
return undefined;
|
|
96
|
+
} catch {
|
|
97
|
+
return undefined;
|
|
98
|
+
} finally {
|
|
99
|
+
clearTimeout(timeoutId);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
32
103
|
const DEFAULT_WIDGET_ASSET_BASE =
|
|
33
104
|
"https://unpkg.com/@eka-care/medassist-widget@latest/dist/";
|
|
34
105
|
|
|
@@ -81,35 +152,64 @@
|
|
|
81
152
|
return;
|
|
82
153
|
}
|
|
83
154
|
|
|
84
|
-
|
|
85
|
-
|
|
155
|
+
let title = urlParams.get("title") || "Medi Clinic";
|
|
156
|
+
let iconUrl = urlParams.get("iconUrl") || undefined;
|
|
86
157
|
const context = urlParams.get("context");
|
|
87
|
-
const baseUrl = urlParams.get("baseUrl") ||
|
|
158
|
+
const baseUrl = urlParams.get("baseUrl") || "https://matrix.eka.care/reloaded";
|
|
88
159
|
const environment =
|
|
89
160
|
getEnvironment(urlParams.get("environment")) ?? "production";
|
|
161
|
+
const attributeTheme = urlParams.get("theme")
|
|
162
|
+
? (() => {
|
|
163
|
+
try {
|
|
164
|
+
return JSON.parse(urlParams.get("theme") || "{}") as WidgetTheme;
|
|
165
|
+
} catch {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
})()
|
|
169
|
+
: undefined;
|
|
90
170
|
const container = document.getElementById("root") || document.body;
|
|
91
171
|
try {
|
|
92
|
-
await Promise.all([
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
172
|
+
await Promise.all([loadWidgetCss(), loadWidgetScript()]);
|
|
173
|
+
if (
|
|
174
|
+
!window?.renderMedAssist ||
|
|
175
|
+
typeof window?.renderMedAssist !== "function"
|
|
176
|
+
) {
|
|
97
177
|
throw new Error("renderMedAssist is not available on window");
|
|
98
178
|
}
|
|
99
179
|
|
|
180
|
+
// Fetch agent-config when baseUrl is available; 10s timeout aborts pending request
|
|
181
|
+
let apiTheme: WidgetTheme | undefined;
|
|
182
|
+
console.log("base url", baseUrl);
|
|
183
|
+
|
|
184
|
+
if (baseUrl) {
|
|
185
|
+
try {
|
|
186
|
+
const agentConfig = await fetchAgentConfig(baseUrl, agentId);
|
|
187
|
+
title = agentConfig?.name ?? title;
|
|
188
|
+
iconUrl = agentConfig?.theme?.icon_img ?? iconUrl;
|
|
189
|
+
apiTheme = mapAgentConfigThemeToWidgetTheme(
|
|
190
|
+
agentConfig?.theme ?? undefined
|
|
191
|
+
);
|
|
192
|
+
} catch {
|
|
193
|
+
// ignore; use URL params only
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
100
197
|
const config = {
|
|
101
198
|
title,
|
|
102
199
|
iconUrl,
|
|
103
200
|
environment,
|
|
104
201
|
onClose: () => {
|
|
105
|
-
// Send message to parent window to close iframe
|
|
106
202
|
if (window.parent !== window) {
|
|
107
203
|
window.parent.postMessage({ type: "WIDGET_CLOSE" }, "*");
|
|
108
204
|
}
|
|
109
205
|
},
|
|
110
206
|
context: context ? JSON.parse(context) : undefined,
|
|
111
207
|
baseUrl,
|
|
112
|
-
displayMode: "full" as "full" | "widget"
|
|
208
|
+
displayMode: "full" as "full" | "widget",
|
|
209
|
+
theme: {
|
|
210
|
+
...(apiTheme ?? {}),
|
|
211
|
+
...(attributeTheme ?? {}),
|
|
212
|
+
},
|
|
113
213
|
};
|
|
114
214
|
window.renderMedAssist(container, agentId, config);
|
|
115
215
|
} catch (error) {
|
package/index.ts
CHANGED
|
@@ -38,6 +38,19 @@ const DEFAULT_WIDGET_ASSET_BASE = (() => {
|
|
|
38
38
|
return "https://unpkg.com/@eka-care/medassist-widget@latest/dist/";
|
|
39
39
|
})();
|
|
40
40
|
|
|
41
|
+
/** Theme from agent-config API (has mode; textColor derived: dark → black, light → white) */
|
|
42
|
+
type AgentConfig = {
|
|
43
|
+
name?: string;
|
|
44
|
+
theme?: {
|
|
45
|
+
background?: string;
|
|
46
|
+
background_img?: string;
|
|
47
|
+
accent?: string;
|
|
48
|
+
mode?: "light" | "dark";
|
|
49
|
+
title_img?: string;
|
|
50
|
+
icon_img?: string
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
41
54
|
type MedAssistInitConfig = {
|
|
42
55
|
auth?: string;
|
|
43
56
|
agentId?: string;
|
|
@@ -45,9 +58,43 @@ type MedAssistInitConfig = {
|
|
|
45
58
|
title?: string;
|
|
46
59
|
iconUrl?: string;
|
|
47
60
|
baseUrl?: string;
|
|
61
|
+
theme?: {
|
|
62
|
+
background?: string;
|
|
63
|
+
backgroundImage?: string;
|
|
64
|
+
primary?: string;
|
|
65
|
+
textColor?: "black" | "white";
|
|
66
|
+
};
|
|
48
67
|
[key: string]: unknown;
|
|
49
68
|
};
|
|
50
69
|
|
|
70
|
+
/** Map agent-config API theme to widget theme (mode → textColor: dark→black, light→white) */
|
|
71
|
+
function mapAgentConfigThemeToWidgetTheme(apiTheme: AgentConfig["theme"] | undefined): MedAssistInitConfig["theme"] {
|
|
72
|
+
if (!apiTheme) return undefined;
|
|
73
|
+
const textColor = apiTheme.mode === "dark" ? "white" : apiTheme.mode === "light" ? "black" : undefined;
|
|
74
|
+
return {
|
|
75
|
+
...(apiTheme.background && { background: apiTheme.background }),
|
|
76
|
+
...(apiTheme.background_img && { backgroundImage: apiTheme.background_img }),
|
|
77
|
+
...(apiTheme.accent && { primary: apiTheme.accent }),
|
|
78
|
+
...(textColor && { textColor }),
|
|
79
|
+
...(apiTheme.title_img && { titleImg: apiTheme.title_img }),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Fetch agent-config from API and return theme from response data */
|
|
84
|
+
async function fetchAgentConfig(baseUrl: string, agentId: string): Promise<AgentConfig | undefined> {
|
|
85
|
+
const url = `${baseUrl.replace(/\/$/, "")}/med-assist/agent-config/${agentId}`;
|
|
86
|
+
const res = await fetch(url, {
|
|
87
|
+
headers: {
|
|
88
|
+
"ngrok-skip-browser-warning": "69420",
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (!res.ok) return undefined;
|
|
93
|
+
const json = await res.json();
|
|
94
|
+
if (json?.success && json?.data?.theme) return json.data as AgentConfig;
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
51
98
|
interface EkaMedAssistWindow extends Window {
|
|
52
99
|
EkaMedAssist?: {
|
|
53
100
|
init: (config: MedAssistInitConfig) => void;
|
|
@@ -312,14 +359,15 @@ class MedAssistWidgetLoader extends HTMLElement {
|
|
|
312
359
|
const button = shadowRoot.getElementById("medassist-open-btn");
|
|
313
360
|
const rootElement = shadowRoot.getElementById("medassist-widget-root");
|
|
314
361
|
const agentId = this.getAttribute("agent-id");
|
|
315
|
-
|
|
362
|
+
let iconUrl = this.getAttribute("icon-url") || this.defaultIconUrl;
|
|
316
363
|
const environment =
|
|
317
364
|
getEnvironment(this.getAttribute("environment")) ?? "production";
|
|
318
|
-
|
|
319
|
-
const baseUrl = this.getAttribute("base-url") ||
|
|
365
|
+
let title = this.getAttribute("title") || "Medi Clinic";
|
|
366
|
+
const baseUrl = this.getAttribute("base-url") || "https://matrix.eka.care/reloaded";
|
|
320
367
|
const displayModeAttribute = this.getAttribute("display-mode");
|
|
321
368
|
const displayMode: "full" | "widget" = displayModeAttribute === "full" ? "full" : "widget";
|
|
322
369
|
const attributeContext = this.getAttribute("context") ? JSON.parse(this.getAttribute("context") || "{}") : undefined;
|
|
370
|
+
const attributeTheme = this.getAttribute("theme") ? (() => { try { return JSON.parse(this.getAttribute("theme") || "{}"); } catch { return undefined; } })() : undefined;
|
|
323
371
|
|
|
324
372
|
const initConfig = (typeof window !== "undefined"
|
|
325
373
|
? (window as EkaMedAssistWindow).__ekaMedAssistConfig__
|
|
@@ -332,6 +380,7 @@ class MedAssistWidgetLoader extends HTMLElement {
|
|
|
332
380
|
|
|
333
381
|
const auth = initConfig.auth || undefined;
|
|
334
382
|
const resolvedAgentId = initConfig.agentId || agentId;
|
|
383
|
+
const apiBaseUrl = (initConfig.baseUrl as string) || baseUrl;
|
|
335
384
|
|
|
336
385
|
const customOnClose = typeof window !== "undefined" ? (window as EkaMedAssistWindow).EkaMedAssist?.onClose : undefined;
|
|
337
386
|
|
|
@@ -343,13 +392,26 @@ class MedAssistWidgetLoader extends HTMLElement {
|
|
|
343
392
|
if (!rootElement) {
|
|
344
393
|
console.error("Widget root element is missing");
|
|
345
394
|
return;
|
|
346
|
-
}
|
|
395
|
+
}
|
|
347
396
|
|
|
348
397
|
if (button) {
|
|
349
398
|
button.classList.add("hidden");
|
|
350
399
|
}
|
|
351
400
|
rootElement.classList.remove("hidden");
|
|
352
401
|
|
|
402
|
+
// Fetch agent-config when baseUrl is available; derive theme (mode → textColor: dark→black, light→white)
|
|
403
|
+
let apiTheme: MedAssistInitConfig["theme"] = undefined;
|
|
404
|
+
if (apiBaseUrl) {
|
|
405
|
+
try {
|
|
406
|
+
const agentConfig = await fetchAgentConfig(apiBaseUrl, resolvedAgentId);
|
|
407
|
+
title = agentConfig?.name || title;
|
|
408
|
+
iconUrl = agentConfig?.theme?.icon_img || iconUrl;
|
|
409
|
+
apiTheme = mapAgentConfigThemeToWidgetTheme(agentConfig?.theme || undefined);
|
|
410
|
+
} catch {
|
|
411
|
+
// ignore; use attribute + init theme only
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
353
415
|
const widgetConfig = {
|
|
354
416
|
title: (initConfig.title as string) || title,
|
|
355
417
|
iconUrl: (initConfig.iconUrl as string) || iconUrl,
|
|
@@ -364,10 +426,11 @@ class MedAssistWidgetLoader extends HTMLElement {
|
|
|
364
426
|
rootElement.classList.add("hidden");
|
|
365
427
|
|
|
366
428
|
},
|
|
367
|
-
baseUrl:
|
|
429
|
+
baseUrl: apiBaseUrl,
|
|
368
430
|
context: mergedContext,
|
|
369
431
|
displayMode,
|
|
370
|
-
auth
|
|
432
|
+
auth,
|
|
433
|
+
theme: { ...(apiTheme || {}), ...(attributeTheme || {}), ...(initConfig.theme || {}) }
|
|
371
434
|
};
|
|
372
435
|
|
|
373
436
|
if (this.widgetLoaded) {
|