not working
This commit is contained in:
123
public/app.js
123
public/app.js
@@ -32,126 +32,3 @@ if (slides.length > 0) {
|
|||||||
setInterval(nextSlide, 10000);
|
setInterval(nextSlide, 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
(function () {
|
|
||||||
const preamble = `
|
|
||||||
We use what we preach — this chatbot is powered by our own n8n automation 🤖 to help you quickly find what you need.
|
|
||||||
|
|
||||||
Want to talk to a real automation expert? Just buy a service pack 💼 — it includes a 1-hour get-to-know session with our team 👥.
|
|
||||||
|
|
||||||
If it’s not the right fit, no worries — we’ll refund you 💸.
|
|
||||||
`;
|
|
||||||
|
|
||||||
const logo="logo.svg"
|
|
||||||
const api='https://ai.odoo4projects.com/webhook/81742473-b50b-4845-a5f9-916d9fe60876/chat'
|
|
||||||
|
|
||||||
// Elements
|
|
||||||
const chatToggle = document.getElementById('cw-chatToggle');
|
|
||||||
const chatWidget = document.getElementById('cw-chatWidget');
|
|
||||||
const chatForm = document.getElementById('cw-chatForm');
|
|
||||||
const chatInput = document.getElementById('cw-chatInput');
|
|
||||||
const chatMessages = document.getElementById('cw-chatMessages');
|
|
||||||
const sessionId = crypto.randomUUID();
|
|
||||||
|
|
||||||
let chatOpened = false;
|
|
||||||
|
|
||||||
function appendMessage(text, sender) {
|
|
||||||
const msg = document.createElement('div');
|
|
||||||
msg.classList.add('cw-message', sender === 'user' ? 'user' : 'bot');
|
|
||||||
msg.innerHTML = text;
|
|
||||||
|
|
||||||
chatMessages.appendChild(msg);
|
|
||||||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
chatToggle.addEventListener('click', () => {
|
|
||||||
const isVisible = chatWidget.classList.toggle('active');
|
|
||||||
if (isVisible && !chatOpened) {
|
|
||||||
appendMessage(
|
|
||||||
preamble,
|
|
||||||
'bot'
|
|
||||||
);
|
|
||||||
chatOpened = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
chatForm.addEventListener('submit', async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const input = chatInput.value.trim();
|
|
||||||
if (!input) return;
|
|
||||||
appendMessage(input, 'user');
|
|
||||||
chatInput.value = '';
|
|
||||||
chatInput.focus();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(api, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ action: 'sendMessage', sessionId, chatInput: input })
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
console.log("12344")
|
|
||||||
const statusDiv = document.getElementById('cw-status');
|
|
||||||
console.log("ASS")
|
|
||||||
console.log(data)
|
|
||||||
if (data.status) {
|
|
||||||
statusDiv.innerHTML = data.status;
|
|
||||||
|
|
||||||
// Wait one frame to ensure DOM is updated
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
|
|
||||||
statusDiv.style.padding = '10px';
|
|
||||||
statusDiv.style.maxHeight = statusDiv.scrollHeight + 'px';
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
statusDiv.style.maxHeight = '0';
|
|
||||||
statusDiv.style.padding = '0 10px';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
appendMessage(data.output, 'bot');
|
|
||||||
} catch (error) {
|
|
||||||
appendMessage('Fehler beim Verbinden mit dem Server. Bitte versuchen Sie es später erneut.', 'bot');
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleBuyClick(buttonId, message) {
|
|
||||||
const btn = document.getElementById(buttonId);
|
|
||||||
if (!btn) return;
|
|
||||||
|
|
||||||
btn.addEventListener('click', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
if (!chatWidget.classList.contains('active')) {
|
|
||||||
chatWidget.classList.add('active');
|
|
||||||
if (!chatOpened) {
|
|
||||||
appendMessage(preamble, 'bot');
|
|
||||||
chatOpened = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
appendMessage(message, 'user');
|
|
||||||
|
|
||||||
fetch(api, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ action: 'sendMessage', sessionId, chatInput: message })
|
|
||||||
})
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then((data) => {
|
|
||||||
appendMessage(data.output, 'bot');
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
appendMessage('Fehler beim Verbinden mit dem Server. Bitte versuchen Sie es später erneut.', 'bot');
|
|
||||||
console.error(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleBuyClick('buy-3h', 'I want to buy the 3 Hours pack for $450.');
|
|
||||||
handleBuyClick('buy-5h', 'I want to buy the 5 Hours pack for $675.');
|
|
||||||
handleBuyClick('buy-10h', 'I want to buy the 10 Hours pack for $1200.');
|
|
||||||
handleBuyClick('buy-bundle', 'I want to buy the ODOO and N8N bundle for $395 per year.');
|
|
||||||
})();
|
|
||||||
|
|||||||
BIN
public/button.png
Normal file
BIN
public/button.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 MiB |
@@ -9,22 +9,9 @@
|
|||||||
<meta name="author" content="OD8N">
|
<meta name="author" content="OD8N">
|
||||||
<title>OD8N - Odoo & n8n Automation Experts</title>
|
<title>OD8N - Odoo & n8n Automation Experts</title>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<button id="cw-chatToggle" aria-label="Toggle chat widget" type="button">
|
|
||||||
<img src="logo.svg" alt="Logo"><span class="text-xs">Agent</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div id="cw-chatWidget" role="region" aria-live="polite" aria-label="Customer support chat widget">
|
<script src="widget/widget.js"></script>
|
||||||
<div class="logo-container">
|
|
||||||
<img src="logo.svg" alt="Logo" />
|
|
||||||
</div>
|
|
||||||
<div class="header">Kundenservice</div>
|
|
||||||
<div id="cw-status"></div>
|
|
||||||
<div id="cw-chatMessages"></div>
|
|
||||||
<form id="cw-chatForm" autocomplete="off">
|
|
||||||
<input type="text" id="cw-chatInput" placeholder="Type your message..." required autocomplete="off" />
|
|
||||||
<button type="submit">Senden</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
{
|
{
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
|
|||||||
351
public/widget.js
Normal file
351
public/widget.js
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
|
||||||
|
(function () {
|
||||||
|
const preamble = `
|
||||||
|
We use what we preach — this chatbot is powered by our own n8n automation 🤖 to help you quickly find what you need.
|
||||||
|
|
||||||
|
Want to talk to a real automation expert? Just buy a service pack 💼 — it includes a 1-hour get-to-know session with our team 👥.
|
||||||
|
|
||||||
|
If it’s not the right fit, no worries — we’ll refund you 💸.
|
||||||
|
`;
|
||||||
|
|
||||||
|
const logo="logo.svg"
|
||||||
|
const api='https://ai.odoo4projects.com/webhook/81742473-b50b-4845-a5f9-916d9fe60876/chat'
|
||||||
|
|
||||||
|
// Elements
|
||||||
|
const chatToggle = document.getElementById('cw-chatToggle');
|
||||||
|
const chatWidget = document.getElementById('cw-chatWidget');
|
||||||
|
const chatForm = document.getElementById('cw-chatForm');
|
||||||
|
const chatInput = document.getElementById('cw-chatInput');
|
||||||
|
const chatMessages = document.getElementById('cw-chatMessages');
|
||||||
|
const sessionId = crypto.randomUUID();
|
||||||
|
|
||||||
|
let chatOpened = false;
|
||||||
|
|
||||||
|
function appendMessage(text, sender) {
|
||||||
|
const msg = document.createElement('div');
|
||||||
|
msg.classList.add('cw-message', sender === 'user' ? 'user' : 'bot');
|
||||||
|
msg.innerHTML = text;
|
||||||
|
|
||||||
|
chatMessages.appendChild(msg);
|
||||||
|
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatToggle.addEventListener('click', () => {
|
||||||
|
const isVisible = chatWidget.classList.toggle('active');
|
||||||
|
if (isVisible && !chatOpened) {
|
||||||
|
appendMessage(
|
||||||
|
preamble,
|
||||||
|
'bot'
|
||||||
|
);
|
||||||
|
chatOpened = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
chatForm.addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const input = chatInput.value.trim();
|
||||||
|
if (!input) return;
|
||||||
|
appendMessage(input, 'user');
|
||||||
|
chatInput.value = '';
|
||||||
|
chatInput.focus();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(api, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ action: 'sendMessage', sessionId, chatInput: input })
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
console.log("12344")
|
||||||
|
const statusDiv = document.getElementById('cw-status');
|
||||||
|
console.log("ASS")
|
||||||
|
console.log(data)
|
||||||
|
if (data.status) {
|
||||||
|
statusDiv.innerHTML = data.status;
|
||||||
|
|
||||||
|
// Wait one frame to ensure DOM is updated
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
|
||||||
|
statusDiv.style.padding = '10px';
|
||||||
|
statusDiv.style.maxHeight = statusDiv.scrollHeight + 'px';
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
statusDiv.style.maxHeight = '0';
|
||||||
|
statusDiv.style.padding = '0 10px';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
appendMessage(data.output, 'bot');
|
||||||
|
} catch (error) {
|
||||||
|
appendMessage('Fehler beim Verbinden mit dem Server. Bitte versuchen Sie es später erneut.', 'bot');
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleBuyClick(buttonId, message) {
|
||||||
|
const btn = document.getElementById(buttonId);
|
||||||
|
if (!btn) return;
|
||||||
|
|
||||||
|
btn.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!chatWidget.classList.contains('active')) {
|
||||||
|
chatWidget.classList.add('active');
|
||||||
|
if (!chatOpened) {
|
||||||
|
appendMessage(preamble, 'bot');
|
||||||
|
chatOpened = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendMessage(message, 'user');
|
||||||
|
|
||||||
|
fetch(api, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ action: 'sendMessage', sessionId, chatInput: message })
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
appendMessage(data.output, 'bot');
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
appendMessage('Fehler beim Verbinden mit dem Server. Bitte versuchen Sie es später erneut.', 'bot');
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleBuyClick('buy-3h', 'I want to buy the 3 Hours pack for $450.');
|
||||||
|
handleBuyClick('buy-5h', 'I want to buy the 5 Hours pack for $675.');
|
||||||
|
handleBuyClick('buy-10h', 'I want to buy the 10 Hours pack for $1200.');
|
||||||
|
handleBuyClick('buy-bundle', 'I want to buy the ODOO and N8N bundle for $395 per year.');
|
||||||
|
})();
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const widgetHTML = `
|
||||||
|
<button id="cw-chatToggle" aria-label="Toggle chat widget" type="button">
|
||||||
|
<img src="logo.svg" alt="Logo"><span class="text-xs">Agent</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div id="cw-chatWidget" role="region" aria-live="polite" aria-label="Customer support chat widget">
|
||||||
|
<div class="logo-container">
|
||||||
|
<img src="logo.svg" alt="Logo" />
|
||||||
|
</div>
|
||||||
|
<div class="header">Kundenservice</div>
|
||||||
|
<div id="cw-status"></div>
|
||||||
|
<div id="cw-chatMessages"></div>
|
||||||
|
<form id="cw-chatForm" autocomplete="off">
|
||||||
|
<input type="text" id="cw-chatInput" placeholder="Type your message..." required autocomplete="off" />
|
||||||
|
<button type="submit">Senden</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.body.insertAdjacentHTML('beforeend', widgetHTML);
|
||||||
|
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
/* cw.css */
|
||||||
|
|
||||||
|
/* Container */
|
||||||
|
#cw-chatToggle {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 24px;
|
||||||
|
right: 24px;
|
||||||
|
background-color: #FFA500;
|
||||||
|
color: white;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-radius: 25px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
z-index: 100000;
|
||||||
|
border: none;
|
||||||
|
user-select: none;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
#cw-chatToggle:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
#cw-chatToggle div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
#cw-chatToggle img {
|
||||||
|
image-rendering: pixelated;
|
||||||
|
image-rendering: optimizeQuality;
|
||||||
|
image-rendering: -webkit-optimize-contrast; /* Chrome */
|
||||||
|
image-rendering: crisp-edges; /* Fallback */
|
||||||
|
}
|
||||||
|
#cw-chatToggle span.text-sm {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.875rem; /* 14px */
|
||||||
|
}
|
||||||
|
#cw-chatToggle span.text-xs {
|
||||||
|
font-size: 0.75rem; /* 12px */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat widget container */
|
||||||
|
#cw-chatWidget {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 100px;
|
||||||
|
right: 24px;
|
||||||
|
width: 500px;
|
||||||
|
max-height: 70vh;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 12px;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 100000;
|
||||||
|
font-family: system-ui, sans-serif;
|
||||||
|
}
|
||||||
|
#cw-chatWidget.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logo container */
|
||||||
|
#cw-chatWidget .logo-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: 16px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
#cw-chatWidget .logo-container img {
|
||||||
|
height: 60px;
|
||||||
|
user-select: none;
|
||||||
|
image-rendering: optimizeQuality;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
image-rendering: -webkit-optimize-contrast; /* Chrome */
|
||||||
|
image-rendering: crisp-edges; /* Fallback */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
#cw-status {
|
||||||
|
padding: 10px 10px;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
max-height: 0;
|
||||||
|
transition: max-height 0.5s ease-in-out, padding 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cw-chatWidget .header {
|
||||||
|
background-color: #0070c0;
|
||||||
|
color: white;
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Messages container */
|
||||||
|
#cw-chatMessages {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 16px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
user-select: text;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat form */
|
||||||
|
#cw-chatForm {
|
||||||
|
display: flex;
|
||||||
|
margin: 0px;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
#cw-chatInput {
|
||||||
|
flex: 1;
|
||||||
|
border: none;
|
||||||
|
padding: 8px 20px;
|
||||||
|
font-size: 1rem;
|
||||||
|
outline-offset: 2px;
|
||||||
|
border-radius: 0 0 0 12px;
|
||||||
|
}
|
||||||
|
#cw-chatInput:focus {
|
||||||
|
outline: 0px solid #0070c0;
|
||||||
|
}
|
||||||
|
#cw-chatForm button {
|
||||||
|
background-color: #0070c0;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
padding: 0 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 0 0 12px 0;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
#cw-chatForm button:hover {
|
||||||
|
background-color: #005a9e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Message bubbles */
|
||||||
|
.cw-message {
|
||||||
|
max-width: 75%;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 12px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
.cw-message.user {
|
||||||
|
background-color: #DCF8C6;
|
||||||
|
color: #333;
|
||||||
|
margin-left: auto;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.cw-message.bot {
|
||||||
|
background-color: #E0E0E0;
|
||||||
|
color: #333;
|
||||||
|
margin-right: auto;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 12px 24px;
|
||||||
|
background-color: #4CAF50; /* Green */
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: background-color 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
background-color: #45a049;
|
||||||
|
box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:active {
|
||||||
|
background-color: #3e8e41;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive adjustments */
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
#cw-chatWidget {
|
||||||
|
width: 90%;
|
||||||
|
max-height: 60vh;
|
||||||
|
bottom: 80px;
|
||||||
|
right: 5%;
|
||||||
|
}
|
||||||
|
#cw-chatToggle {
|
||||||
|
bottom: 16px;
|
||||||
|
right: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
});
|
||||||
184
public/widget/OD8N.css
Normal file
184
public/widget/OD8N.css
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
|
||||||
|
/* Container */
|
||||||
|
#cw-chatToggle {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 24px;
|
||||||
|
right: 24px;
|
||||||
|
background-color: #FFA500;
|
||||||
|
color: white;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-radius: 25px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
z-index: 100000;
|
||||||
|
border: none;
|
||||||
|
user-select: none;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
#cw-chatToggle:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
#cw-chatToggle div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
#cw-chatToggle img {
|
||||||
|
image-rendering: pixelated;
|
||||||
|
image-rendering: optimizeQuality;
|
||||||
|
image-rendering: -webkit-optimize-contrast; /* Chrome */
|
||||||
|
image-rendering: crisp-edges; /* Fallback */
|
||||||
|
}
|
||||||
|
#cw-chatToggle span.text-sm {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.875rem; /* 14px */
|
||||||
|
}
|
||||||
|
#cw-chatToggle span.text-xs {
|
||||||
|
font-size: 0.75rem; /* 12px */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat widget container */
|
||||||
|
#cw-chatWidget {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 100px;
|
||||||
|
right: 24px;
|
||||||
|
width: 500px;
|
||||||
|
max-height: 70vh;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 12px;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 100000;
|
||||||
|
font-family: system-ui, sans-serif;
|
||||||
|
}
|
||||||
|
#cw-chatWidget.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logo container */
|
||||||
|
#cw-chatWidget .logo-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: 16px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
#cw-chatWidget .logo-container img {
|
||||||
|
height: 60px;
|
||||||
|
user-select: none;
|
||||||
|
image-rendering: optimizeQuality;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
image-rendering: -webkit-optimize-contrast; /* Chrome */
|
||||||
|
image-rendering: crisp-edges; /* Fallback */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
#cw-status {
|
||||||
|
padding: 10px 10px;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
max-height: 0;
|
||||||
|
transition: max-height 0.5s ease-in-out, padding 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cw-chatWidget .header {
|
||||||
|
background-color: #0070c0;
|
||||||
|
color: white;
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Messages container */
|
||||||
|
#cw-chatMessages {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 16px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
user-select: text;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat form */
|
||||||
|
#cw-chatForm {
|
||||||
|
display: flex;
|
||||||
|
margin: 0px;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
#cw-chatInput {
|
||||||
|
flex: 1;
|
||||||
|
border: none;
|
||||||
|
padding: 8px 20px;
|
||||||
|
font-size: 1rem;
|
||||||
|
outline-offset: 2px;
|
||||||
|
border-radius: 0 0 0 12px;
|
||||||
|
}
|
||||||
|
#cw-chatInput:focus {
|
||||||
|
outline: 0px solid #0070c0;
|
||||||
|
}
|
||||||
|
#cw-chatForm button {
|
||||||
|
background-color: #0070c0;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
padding: 0 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 0 0 12px 0;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
#cw-chatForm button:hover {
|
||||||
|
background-color: #005a9e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Message bubbles */
|
||||||
|
.cw-message {
|
||||||
|
max-width: 75%;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 12px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
.cw-message.user {
|
||||||
|
background-color: #DCF8C6;
|
||||||
|
color: #333;
|
||||||
|
margin-left: auto;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.cw-message.bot {
|
||||||
|
background-color: #E0E0E0;
|
||||||
|
color: #333;
|
||||||
|
margin-right: auto;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 12px 24px;
|
||||||
|
background-color: #4CAF50; /* Green */
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: background-color 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
background-color: #45a049;
|
||||||
|
box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:active {
|
||||||
|
background-color: #3e8e41;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
169
public/widget/widget.js
Normal file
169
public/widget/widget.js
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
<button id="cw-chatToggle" aria-label="Toggle chat widget" type="button">
|
||||||
|
<img src="logo.svg" alt="Logo"><span class="text-xs">Agent</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div id="cw-chatWidget" role="region" aria-live="polite" aria-label="Customer support chat widget">
|
||||||
|
<div class="logo-container">
|
||||||
|
<img src="logo.svg" alt="Logo" />
|
||||||
|
</div>
|
||||||
|
<div class="header">Kundenservice</div>
|
||||||
|
<div id="cw-status"></div>
|
||||||
|
<div id="cw-chatMessages"></div>
|
||||||
|
<form id="cw-chatForm" autocomplete="off">
|
||||||
|
<input type="text" id="cw-chatInput" placeholder="Type your message..." required autocomplete="off" />
|
||||||
|
<button type="submit">Senden</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const preamble = `
|
||||||
|
We use what we preach — this chatbot is powered by our own n8n automation 🤖 to help you quickly find what you need.
|
||||||
|
|
||||||
|
Want to talk to a real automation expert? Just buy a service pack 💼 — it includes a 1-hour get-to-know session with our team 👥.
|
||||||
|
|
||||||
|
If it’s not the right fit, no worries — we’ll refund you 💸.
|
||||||
|
`;
|
||||||
|
|
||||||
|
const logo="logo.svg"
|
||||||
|
const api='https://ai.odoo4projects.com/webhook/81742473-b50b-4845-a5f9-916d9fe60876/chat'
|
||||||
|
|
||||||
|
// Elements
|
||||||
|
const chatToggle = document.getElementById('cw-chatToggle');
|
||||||
|
const chatWidget = document.getElementById('cw-chatWidget');
|
||||||
|
const chatForm = document.getElementById('cw-chatForm');
|
||||||
|
const chatInput = document.getElementById('cw-chatInput');
|
||||||
|
const chatMessages = document.getElementById('cw-chatMessages');
|
||||||
|
const sessionId = crypto.randomUUID();
|
||||||
|
|
||||||
|
let chatOpened = false;
|
||||||
|
|
||||||
|
function appendMessage(text, sender) {
|
||||||
|
const msg = document.createElement('div');
|
||||||
|
msg.classList.add('cw-message', sender === 'user' ? 'user' : 'bot');
|
||||||
|
msg.innerHTML = text;
|
||||||
|
|
||||||
|
chatMessages.appendChild(msg);
|
||||||
|
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatToggle.addEventListener('click', () => {
|
||||||
|
const isVisible = chatWidget.classList.toggle('active');
|
||||||
|
if (isVisible && !chatOpened) {
|
||||||
|
appendMessage(
|
||||||
|
preamble,
|
||||||
|
'bot'
|
||||||
|
);
|
||||||
|
chatOpened = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
chatForm.addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const input = chatInput.value.trim();
|
||||||
|
if (!input) return;
|
||||||
|
appendMessage(input, 'user');
|
||||||
|
chatInput.value = '';
|
||||||
|
chatInput.focus();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(api, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ action: 'sendMessage', sessionId, chatInput: input })
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
console.log("12344")
|
||||||
|
const statusDiv = document.getElementById('cw-status');
|
||||||
|
console.log("ASS")
|
||||||
|
console.log(data)
|
||||||
|
if (data.status) {
|
||||||
|
statusDiv.innerHTML = data.status;
|
||||||
|
|
||||||
|
// Wait one frame to ensure DOM is updated
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
|
||||||
|
statusDiv.style.padding = '10px';
|
||||||
|
statusDiv.style.maxHeight = statusDiv.scrollHeight + 'px';
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
statusDiv.style.maxHeight = '0';
|
||||||
|
statusDiv.style.padding = '0 10px';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
appendMessage(data.output, 'bot');
|
||||||
|
} catch (error) {
|
||||||
|
appendMessage('Fehler beim Verbinden mit dem Server. Bitte versuchen Sie es später erneut.', 'bot');
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleBuyClick(buttonId, message) {
|
||||||
|
const btn = document.getElementById(buttonId);
|
||||||
|
if (!btn) return;
|
||||||
|
|
||||||
|
btn.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!chatWidget.classList.contains('active')) {
|
||||||
|
chatWidget.classList.add('active');
|
||||||
|
if (!chatOpened) {
|
||||||
|
appendMessage(preamble, 'bot');
|
||||||
|
chatOpened = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendMessage(message, 'user');
|
||||||
|
|
||||||
|
fetch(api, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ action: 'sendMessage', sessionId, chatInput: message })
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
appendMessage(data.output, 'bot');
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
appendMessage('Fehler beim Verbinden mit dem Server. Bitte versuchen Sie es später erneut.', 'bot');
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleBuyClick('buy-3h', 'I want to buy the 3 Hours pack for $450.');
|
||||||
|
handleBuyClick('buy-5h', 'I want to buy the 5 Hours pack for $675.');
|
||||||
|
handleBuyClick('buy-10h', 'I want to buy the 10 Hours pack for $1200.');
|
||||||
|
handleBuyClick('buy-bundle', 'I want to buy the ODOO and N8N bundle for $395 per year.');
|
||||||
|
})();
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const widgetHTML = `
|
||||||
|
<button id="cw-chatToggle" aria-label="Toggle chat widget" type="button">
|
||||||
|
<img src="logo.svg" alt="Logo"><span class="text-xs">Agent</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div id="cw-chatWidget" role="region" aria-live="polite" aria-label="Customer support chat widget">
|
||||||
|
<div class="logo-container">
|
||||||
|
<img src="logo.svg" alt="Logo" />
|
||||||
|
</div>
|
||||||
|
<div class="header">Kundenservice</div>
|
||||||
|
<div id="cw-status"></div>
|
||||||
|
<div id="cw-chatMessages"></div>
|
||||||
|
<form id="cw-chatForm" autocomplete="off">
|
||||||
|
<input type="text" id="cw-chatInput" placeholder="Type your message..." required autocomplete="off" />
|
||||||
|
<button type="submit">Senden</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.body.insertAdjacentHTML('beforeend', widgetHTML);
|
||||||
|
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user