Passa al contenuto principale

Architettura del Widget Preact

Shadow DOM + Preact Implementation

Il nuovo widget combina Shadow DOM con Preact per un'esperienza di sviluppo moderna e performante:

resources/js/shadowDomWidgetPreact.jsx
import { render, Fragment, h } from "preact";
import { memo } from "preact/compat";
import {
useState,
useEffect,
useRef,
useCallback,
useMemo,
} from "preact/hooks";

// Custom Shadow DOM renderer for Preact
function createShadowRenderer(shadowRoot) {
return {
render: (component) => render(component, shadowRoot),
};
}

class TidikoAiWidgetPreact {
constructor(containerId = null, params = {}) {
// Configurazione del widget
this.options = { ...platformSettings, ...overrideSettings };
this.jwt = jwt;
this.appUrl = appUrl;
this.type = type;

// Inizializzazione
this.init(containerId);
}

async init(containerId) {
// Creazione del container
const host = containerId
? document.getElementById(containerId)
: this._createDefaultContainer();

if (!host) {
console.error("Container not found");
return;
}

// Attach Shadow DOM
this.shadowRoot = host.attachShadow({ mode: "open" });
await this._injectContent();
this._renderWidget();
}

_renderWidget() {
// Create shadow DOM renderer and render the widget
const renderer = createShadowRenderer(this.shadowRoot);
renderer.render(
<TidikoWidget
options={this.options}
payload={this.payload}
collectionName={this.collectionName}
// ... altri props
/>
);
}
}

Architettura a Componenti Preact

Il widget è ora strutturato come una gerarchia di componenti Preact ottimizzati:

resources/js/shadowDomWidgetPreact.jsx
// Componente principale del widget
const TidikoWidget = ({
options,
payload,
collectionName,
companyName,
// ... altri props
}) => {
// State management con hooks
const [currentThreadId, setCurrentThreadId] = useState(null);
const [isRunning, setIsRunning] = useState(false);
const [messages, setMessages] = useState([]);
const [currentMessage, setCurrentMessage] = useState("");
const [showTools, setShowTools] = useState(false);
const [showPrivacy, setShowPrivacy] = useState(false);
const [showFAQ, setShowFAQ] = useState(false);
// ... altri state

return (
<div className={wrapperClass} style={wrapperStyle}>
<div className={containerClass}>
<ChatHeader
options={options}
showTools={showTools && !isCollapsed}
copyMessage={copyMessage}
onCopyChat={handleCopyChat}
onTrashChat={handleClearChat}
onCloseChat={handleCloseChat}
/>

<ChatHistory
messages={messages}
showFAQ={showFAQ && !isCollapsed}
faqQuestions={options.faqMessages}
showPrivacy={showPrivacy}
options={options}
isRunning={isRunning}
linksTarget={linksTarget}
onFAQQuestionClick={handleFAQQuestionClick}
onPrivacyAccept={handlePrivacyAccept}
onScroll={handleScroll}
onLinkClick={handleLinkClick}
language={language}
isHistoryLoading={isHistoryLoading}
/>

<MessageForm
message={currentMessage}
placeholder={placeholder}
isRunning={isRunning}
isSocketConnected={isSocketConnected}
onMessageChange={handleMessageChange}
onSubmit={handleSubmit}
onKeyDown={handleKeyDown}
onFocus={handleShowChatHistory}
privacyAccepted={showPrivacy}
/>

<div className="chat-footer">
<div className="chat-copyright">
Powered by{" "}
<a
href="https://tidiko.ai"
target="_blank"
rel="noopener"
>
Tidiko.ai
</a>
</div>
</div>
</div>

<button className="open-chat-toggle" onClick={handleToggleChat}>
<ChatToggleIcon />
</button>
</div>
);
};