@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/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
- const title = urlParams.get("title") || "Medi Clinic";
85
- const iconUrl = urlParams.get("iconUrl") || undefined;
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") || undefined;
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
- loadWidgetCss(),
94
- loadWidgetScript(),
95
- ])
96
- if (!window?.renderMedAssist || typeof window?.renderMedAssist !== "function") {
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",//for iframe default display mode is full
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
- const iconUrl = this.getAttribute("icon-url") || this.defaultIconUrl;
362
+ let iconUrl = this.getAttribute("icon-url") || this.defaultIconUrl;
316
363
  const environment =
317
364
  getEnvironment(this.getAttribute("environment")) ?? "production";
318
- const title = this.getAttribute("title") || "Medi Clinic";
319
- const baseUrl = this.getAttribute("base-url") || undefined;
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: (initConfig.baseUrl as string) || 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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eka-care/medassist-widget-embed",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "Embeddable MedAssist widget loader built with Web Components.",
5
5
  "author": "Geethanjali S",
6
6
  "license": "MIT",