mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
feat: embed website widget on login page via admin config endpoint
Fetches /api/config/widget from the sidecar and injects widget.js only when enabled + embed.loginPage + key are all set. Falls back to VITE_API_URL as the script host when cfg.url is empty (default for fresh configs). Replaces an earlier draft that read VITE_WIDGET_KEY + VITE_WIDGET_URL from build-time env — widget config lives in data/widget.json on the sidecar now and is admin-editable via PUT /api/config/widget, so no rebuild is needed to toggle or rotate it. Never blocks login on a widget-config failure — the fetch is fire-and-forget and errors just log a warning. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faEye, faEyeSlash } from '@fortawesome/pro-duotone-svg-icons';
|
import { faEye, faEyeSlash } from '@fortawesome/pro-duotone-svg-icons';
|
||||||
@@ -19,6 +19,46 @@ export const LoginPage = () => {
|
|||||||
const { isOpen, activeAction, close } = useMaintShortcuts();
|
const { isOpen, activeAction, close } = useMaintShortcuts();
|
||||||
const { tokens } = useThemeTokens();
|
const { tokens } = useThemeTokens();
|
||||||
|
|
||||||
|
// Load website widget on login page.
|
||||||
|
//
|
||||||
|
// Config comes from the admin-editable sidecar endpoint (not env vars)
|
||||||
|
// so it can be toggled / rotated / moved at runtime. The widget renders
|
||||||
|
// only when all of enabled + embed.loginPage + key are set.
|
||||||
|
//
|
||||||
|
// `url` may be empty (default for fresh configs) — in that case we fall
|
||||||
|
// back to the same origin the app is talking to for its API, since in
|
||||||
|
// practice the sidecar serves /widget.js alongside /api/*.
|
||||||
|
useEffect(() => {
|
||||||
|
let cancelled = false;
|
||||||
|
const apiUrl = import.meta.env.VITE_API_URL ?? '';
|
||||||
|
if (!apiUrl) return;
|
||||||
|
|
||||||
|
fetch(`${apiUrl}/api/config/widget`)
|
||||||
|
.then(r => (r.ok ? r.json() : null))
|
||||||
|
.then((cfg: { enabled?: boolean; key?: string; url?: string; embed?: { loginPage?: boolean } } | null) => {
|
||||||
|
if (cancelled || !cfg) return;
|
||||||
|
if (!cfg.enabled || !cfg.embed?.loginPage || !cfg.key) return;
|
||||||
|
if (document.getElementById('helix-widget-script')) return;
|
||||||
|
|
||||||
|
const host = cfg.url && cfg.url.length > 0 ? cfg.url : apiUrl;
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.id = 'helix-widget-script';
|
||||||
|
script.src = `${host}/widget.js`;
|
||||||
|
script.setAttribute('data-key', cfg.key);
|
||||||
|
document.body.appendChild(script);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
// Never block login on a widget config failure.
|
||||||
|
console.warn('[widget] config fetch failed', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
document.getElementById('helix-widget-script')?.remove();
|
||||||
|
document.getElementById('helix-widget-host')?.remove();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const saved = localStorage.getItem('helix_remember');
|
const saved = localStorage.getItem('helix_remember');
|
||||||
const savedCreds = saved ? JSON.parse(saved) : null;
|
const savedCreds = saved ? JSON.parse(saved) : null;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user