wineater-bot 2.1.4 → 3.0.1
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/wineater-chatbot.mjs +2756 -2213
- package/dist/wineater-chatbot.umd.js +416 -33
- package/index.html +3 -2
- package/package.json +1 -1
- package/src/index.js +119 -128
- package/src/js/api.js +26 -1
- package/src/js/i18n.js +56 -4
- package/src/js/widget-styles.js +319 -0
- package/src/js/widget.js +218 -0
package/index.html
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Chatbot</title>
|
|
7
7
|
<!-- <script type="module" src="https://unpkg.com/wineater-bot@1.0.0/dist/wineater-chatbot.umd.js"></script> -->
|
|
8
|
-
<script>window.wineaterData = {CLIENT_TOKEN: 'K0ZzlrfT0z00J6dSAt8ZEIKWiUfypG1Tyb1ZGtgwuJaF8WZuRKlHfvEMCF9DyytZ', position: 'right-center'};</script
|
|
8
|
+
<script>window.wineaterData = {CLIENT_TOKEN: 'K0ZzlrfT0z00J6dSAt8ZEIKWiUfypG1Tyb1ZGtgwuJaF8WZuRKlHfvEMCF9DyytZ', position: 'right-center'};</script>
|
|
9
|
+
<script type="module" src="./src/index.js"></script>
|
|
9
10
|
</head>
|
|
10
11
|
<body style="margin: 0;">
|
|
11
|
-
<
|
|
12
|
+
<div id="widget-container"></div> <!-- Контейнер для виджета -->
|
|
12
13
|
</body>
|
|
13
14
|
</html>
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,58 +1,74 @@
|
|
|
1
|
-
// src/index.js
|
|
2
|
-
|
|
3
|
-
// Import your CSS here
|
|
4
1
|
import './js/styles.js';
|
|
5
2
|
import { setCookie, setUniqueUserCookie, getCookie } from './js/analytics.js';
|
|
6
|
-
import flagsmith from 'flagsmith';
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
import flagsmith from 'flagsmith';
|
|
9
4
|
import Tracker from '@openreplay/tracker';
|
|
5
|
+
import { WineWidget } from './js/widget.js';
|
|
6
|
+
import { Chatbot } from './js/chatbot.js';
|
|
7
|
+
import translator from './js/i18n.js';
|
|
8
|
+
import { shouldOpenChatAutomatically } from './js/auto-open.js';
|
|
9
|
+
import { toggleChatWindow, closeChatWindow, openChatWindow } from './js/ui.js';
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
projectKey: "PA8j9fAi49i6g2QnvpNs",
|
|
13
|
-
'__DISABLE_SECURE_MODE': true
|
|
14
|
-
});
|
|
11
|
+
const DEMO_TOKEN = 'tbMTFzLbWcXFgXK8SzyFHA6kIjelFcz5VQABVPbXdXh5XZJCDQH9BcVlrv3DF3kA';
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
class App {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.stores = ['climats', 'telckel', 'biobio', 'weinpoint', 'vinigrandi', 'ampely'];
|
|
16
|
+
this.tracker = new Tracker({ projectKey: "PA8j9fAi49i6g2QnvpNs", '__DISABLE_SECURE_MODE': true });
|
|
17
|
+
this.position = window?.wineaterData?.POSITION || 'right-center';
|
|
18
|
+
this.type = window?.wineaterData?.TYPE || 'chatbot';
|
|
19
|
+
this.store = this.detectStore();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
detectStore() {
|
|
23
|
+
return this.stores.find(store => window.location.href.includes(store)) || null;
|
|
24
|
+
}
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
async initFlagsmith() {
|
|
27
|
+
try {
|
|
28
|
+
await flagsmith.init({
|
|
29
|
+
environmentID: '5RfiDoiqb4dHrNdQvzbkfM',
|
|
30
|
+
cacheFlags: false,
|
|
31
|
+
enableAnalytics: true,
|
|
32
|
+
identity: getCookie('uniqueUserID'),
|
|
33
|
+
});
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error('Flagsmith initialization failed:', error);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
24
38
|
|
|
39
|
+
async initTranslator() {
|
|
40
|
+
const storeName = this.store ? this.store.charAt(0).toUpperCase() + this.store.slice(1) : 'Climats';
|
|
41
|
+
await translator.fetchConfig(storeName || 'Climats');
|
|
42
|
+
}
|
|
25
43
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
window.closeChatWindow = closeChatWindow;
|
|
31
|
-
window.openChatWindow = openChatWindow;
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
export {
|
|
35
|
-
toggleChatWindow,
|
|
36
|
-
closeChatWindow,
|
|
37
|
-
openChatWindow
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
function getUniqueId() {
|
|
41
|
-
const uniqueId = getCookie()
|
|
42
|
-
}
|
|
44
|
+
initCookies() {
|
|
45
|
+
setCookie('chatbotToken', window.wineaterData?.CLIENT_TOKEN || DEMO_TOKEN, 365);
|
|
46
|
+
setUniqueUserCookie();
|
|
47
|
+
}
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
async initializeChatbotOrWidget() {
|
|
50
|
+
if (this.type === 'widget') {
|
|
51
|
+
new WineWidget();
|
|
52
|
+
} else {
|
|
53
|
+
this.createChatbotUI();
|
|
54
|
+
this.setupChatListeners();
|
|
55
|
+
this.setupChatButtonListener();
|
|
56
|
+
applyPositionToChat(this.position);
|
|
57
|
+
const chatbot = new Chatbot();
|
|
58
|
+
chatbot.initialize();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
createChatbotUI() {
|
|
63
|
+
const btnTextOption = flagsmith.getValue('chat-btn-txt');
|
|
64
|
+
const buttonText = window?.wineaterData?.BUTTON_TEXT || translator.translate(`chatButton${btnTextOption}`);
|
|
65
|
+
const chatbotHTML = `
|
|
66
|
+
<div id="chatbot-container">
|
|
67
|
+
<div id="chat-icon">
|
|
68
|
+
<img src="https://landing-static.s3.eu-central-1.amazonaws.com/images/chat-icon.svg" alt="Chat Icon">
|
|
69
|
+
<span>${buttonText}</span>
|
|
70
|
+
</div>
|
|
71
|
+
<div id="chat-window" class="hidden">
|
|
56
72
|
<div id="chat-header">
|
|
57
73
|
<div id="chat-title">
|
|
58
74
|
<h1>${translator.translate('chatTitle')}</h1>
|
|
@@ -73,98 +89,73 @@ function createChatbotUI() {
|
|
|
73
89
|
<img src="https://landing-static.s3.eu-central-1.amazonaws.com/images/logo.svg" alt="Wineater Logo" id="chatbot-logo">
|
|
74
90
|
</a>
|
|
75
91
|
</div>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
92
|
+
</div>
|
|
93
|
+
`;
|
|
94
|
+
document.body.insertAdjacentHTML('beforeend', chatbotHTML);
|
|
95
|
+
}
|
|
79
96
|
|
|
80
|
-
|
|
81
|
-
|
|
97
|
+
setupChatListeners() {
|
|
98
|
+
const closeButton = document.getElementById('close-btn');
|
|
99
|
+
closeButton.addEventListener('click', toggleChatWindow);
|
|
100
|
+
|
|
101
|
+
window.addEventListener('click', event => {
|
|
102
|
+
const chatWindow = document.getElementById('chat-window');
|
|
103
|
+
const chatIcon = document.getElementById('chat-icon');
|
|
104
|
+
if (!chatWindow.contains(event.target) && !chatIcon.contains(event.target)) {
|
|
105
|
+
chatWindow.classList.remove('visible');
|
|
106
|
+
chatIcon.style.display = 'flex';
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
82
110
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
111
|
+
autoOpenChatIfNeeded() {
|
|
112
|
+
const disableAutoOpen = getCookie('disableAutoOpen');
|
|
113
|
+
if (!disableAutoOpen) {
|
|
114
|
+
shouldOpenChatAutomatically();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
87
117
|
|
|
88
|
-
|
|
89
|
-
window.addEventListener('click', function(event) {
|
|
90
|
-
const chatWindow = document.getElementById('chat-window');
|
|
118
|
+
setupChatButtonListener() {
|
|
91
119
|
const chatIcon = document.getElementById('chat-icon');
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
120
|
+
const chatWindow = document.getElementById('chat-window');
|
|
121
|
+
|
|
122
|
+
if (!chatIcon || !chatWindow) {
|
|
123
|
+
console.error('Chat icon or chat window element not found!');
|
|
124
|
+
return;
|
|
95
125
|
}
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
126
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
chatIcon.classList.add('chat-icon-right-center');
|
|
110
|
-
chatWindow.classList.add('right-center-aligned');
|
|
111
|
-
} else {
|
|
112
|
-
// Apply bottom-right or other default classes as needed
|
|
113
|
-
chatIcon.classList.add('chat-icon-bottom-right');
|
|
127
|
+
chatIcon.addEventListener('click', () => {
|
|
128
|
+
const isVisible = chatWindow.classList.contains('visible');
|
|
129
|
+
if (isVisible) {
|
|
130
|
+
chatWindow.classList.remove('visible');
|
|
131
|
+
chatIcon.style.display = 'flex';
|
|
132
|
+
} else {
|
|
133
|
+
chatWindow.classList.add('visible');
|
|
134
|
+
chatIcon.style.display = 'none';
|
|
135
|
+
}
|
|
136
|
+
});
|
|
114
137
|
}
|
|
138
|
+
|
|
139
|
+
async initialize() {
|
|
140
|
+
this.tracker.start();
|
|
141
|
+
await this.initFlagsmith();
|
|
142
|
+
await this.initTranslator();
|
|
143
|
+
this.initCookies();
|
|
144
|
+
await this.initializeChatbotOrWidget();
|
|
145
|
+
this.autoOpenChatIfNeeded();
|
|
146
|
+
}
|
|
115
147
|
}
|
|
116
148
|
|
|
117
|
-
function
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
149
|
+
function applyPositionToChat(position = 'right-center') {
|
|
150
|
+
const chatIcon = document.getElementById('chat-icon');
|
|
151
|
+
if (!chatIcon) return;
|
|
152
|
+
|
|
153
|
+
// Применение классов для позиции
|
|
154
|
+
chatIcon.className = `chat-icon-${position}`;
|
|
121
155
|
}
|
|
122
156
|
|
|
157
|
+
// Initialize the application on DOM ready
|
|
123
158
|
document.addEventListener('DOMContentLoaded', () => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (!disableAutoOpen) {
|
|
128
|
-
shouldOpenChatAutomatically()
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
// If you want to initialize your chatbot automatically when the script is loaded
|
|
133
|
-
if (typeof window !== 'undefined') {
|
|
134
|
-
let position = window?.wineaterData?.POSITION || 'right-center';
|
|
135
|
-
window.addEventListener('DOMContentLoaded', async () => {
|
|
136
|
-
const stores = ['climats', 'telckel', 'biobio', 'weinpoint', 'vinigrandi'];
|
|
137
|
-
const store = stores.find(value => window.location.href.includes(value)) || null;
|
|
138
|
-
let capitalizeStore;
|
|
139
|
-
if (store) {
|
|
140
|
-
capitalizeStore = store.charAt(0).toUpperCase() + store.slice(1);
|
|
141
|
-
if (capitalizeStore === 'Climats') {
|
|
142
|
-
position = 'right-center';
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
await translator.fetchConfig(capitalizeStore || 'Climats');
|
|
146
|
-
setCookie('chatbotToken', window.wineaterData?.CLIENT_TOKEN || DEMO_TOKEN, 365);
|
|
147
|
-
setUniqueUserCookie();
|
|
148
|
-
flagsmith.init({
|
|
149
|
-
environmentID: '5RfiDoiqb4dHrNdQvzbkfM',
|
|
150
|
-
// api:"http://localhost:8000/api/v1/" set this if you are self hosting, and point it to your API
|
|
151
|
-
cacheFlags: false, // stores flags in localStorage cache
|
|
152
|
-
enableAnalytics: true,
|
|
153
|
-
identity: getCookie('uniqueUserID') // See https://docs.flagsmith.com/flag-analytics/ for more info.
|
|
154
|
-
}).then(() => {
|
|
155
|
-
createChatbotUI(); // Create the UI
|
|
156
|
-
setupCloseButton();
|
|
157
|
-
setupOutsideClick();
|
|
158
|
-
toggleChatIconPosition(position);
|
|
159
|
-
const myChatbot = new Chatbot();
|
|
160
|
-
myChatbot.initialize();
|
|
161
|
-
}).catch(() => {
|
|
162
|
-
createChatbotUI(); // Create the UI
|
|
163
|
-
setupCloseButton();
|
|
164
|
-
setupOutsideClick();
|
|
165
|
-
toggleChatIconPosition(position);
|
|
166
|
-
const myChatbot = new Chatbot();
|
|
167
|
-
myChatbot.initialize();
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
}
|
|
159
|
+
const app = new App();
|
|
160
|
+
app.initialize();
|
|
161
|
+
});
|
package/src/js/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// api.js
|
|
2
2
|
|
|
3
|
-
const stores = ['climats', 'telckel', 'biobio', 'weinpoint', 'vinigrandi'];
|
|
3
|
+
const stores = ['climats', 'telckel', 'biobio', 'weinpoint', 'vinigrandi', 'ampely'];
|
|
4
4
|
const DEMO_TOKEN='bMTFzLbWcXFgXK8SzyFHA6kIjelFcz5VQABVPbXdXh5XZJCDQH9BcVlrv3DF3kA';
|
|
5
5
|
|
|
6
6
|
export class Api {
|
|
@@ -83,4 +83,29 @@ export class Api {
|
|
|
83
83
|
throw error;
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
+
async getInstantRecommendations() {
|
|
87
|
+
console.log('Fetching instant recommendations...');
|
|
88
|
+
try {
|
|
89
|
+
const response = await fetch(`${this.baseURL}dish/recommendations/instant`, {
|
|
90
|
+
method: 'POST',
|
|
91
|
+
headers: {
|
|
92
|
+
'Content-Type': 'application/json',
|
|
93
|
+
'Authorization': `Bearer ${this.token}`
|
|
94
|
+
},
|
|
95
|
+
body: JSON.stringify({ store: this.store })
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const data = await response.json();
|
|
99
|
+
|
|
100
|
+
if (!response.ok) {
|
|
101
|
+
throw new Error(`API call failed with status ${response.status}: ${data.message || 'No additional error information'}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
console.log('Instant recommendations:', data);
|
|
105
|
+
return data;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error('Fetching instant recommendations failed:', error.message);
|
|
108
|
+
throw new Error(`Error in getInstantRecommendations: ${error.message}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
86
111
|
}
|
package/src/js/i18n.js
CHANGED
|
@@ -24,7 +24,20 @@ class Translator {
|
|
|
24
24
|
moreInfo: "Plus d'infos",
|
|
25
25
|
winePairingIntro: "Pour ce vin, voici quelques suggestions de plats :",
|
|
26
26
|
askForDinner: "Que voulez-vous manger ce soir?",
|
|
27
|
-
clearChatButton: "Effacer le chat"
|
|
27
|
+
clearChatButton: "Effacer le chat",
|
|
28
|
+
widgetTitle: "Découvrez votre vin",
|
|
29
|
+
widgetSubtitle: "Recherchez par vos préférences",
|
|
30
|
+
searchPlaceholder: "Entrez un mot-clé ou une description",
|
|
31
|
+
searchButton: "Rechercher",
|
|
32
|
+
priceRange: "Gamme de prix",
|
|
33
|
+
wineColor: "Couleur du vin",
|
|
34
|
+
intensity: "Intensité",
|
|
35
|
+
red: "Rouge",
|
|
36
|
+
white: "Blanc",
|
|
37
|
+
rose: "Rosé",
|
|
38
|
+
light: "Léger",
|
|
39
|
+
medium: "Moyen",
|
|
40
|
+
full: "Puissant"
|
|
28
41
|
},
|
|
29
42
|
es: {
|
|
30
43
|
welcomeMessage: "¿Qué vas a comer? Cuéntame tu plato y te recomendaré el maridaje perfecto.",
|
|
@@ -45,7 +58,20 @@ class Translator {
|
|
|
45
58
|
moreInfo: "Más info",
|
|
46
59
|
winePairingIntro: "Para este vino, aquí tienes algunas sugerencias de platos:",
|
|
47
60
|
askForDinner: "¿Qué te gustaría cenar?",
|
|
48
|
-
clearChatButton: "Limpiar el chat"
|
|
61
|
+
clearChatButton: "Limpiar el chat",
|
|
62
|
+
widgetTitle: "Encuentra tu vino",
|
|
63
|
+
widgetSubtitle: "Busca según tus preferencias",
|
|
64
|
+
searchPlaceholder: "Escribe una palabra clave o descripción",
|
|
65
|
+
searchButton: "Buscar",
|
|
66
|
+
priceRange: "Rango de precios",
|
|
67
|
+
wineColor: "Color del vino",
|
|
68
|
+
intensity: "Intensidad",
|
|
69
|
+
red: "Tinto",
|
|
70
|
+
white: "Blanco",
|
|
71
|
+
rose: "Rosado",
|
|
72
|
+
light: "Ligero",
|
|
73
|
+
medium: "Medio",
|
|
74
|
+
full: "Intenso"
|
|
49
75
|
},
|
|
50
76
|
en: {
|
|
51
77
|
welcomeMessage: "What are you planning to eat? Share your dish and I'll recommend the perfect wine pairing for your meal.",
|
|
@@ -66,7 +92,20 @@ class Translator {
|
|
|
66
92
|
moreInfo: "More info",
|
|
67
93
|
winePairingIntro: "For this wine, here are some suggested dishes:",
|
|
68
94
|
askForDinner: "What would you like to have for dinner?",
|
|
69
|
-
clearChatButton: "Clear Chat"
|
|
95
|
+
clearChatButton: "Clear Chat",
|
|
96
|
+
widgetTitle: "Discover Your Wine",
|
|
97
|
+
widgetSubtitle: "Search by your preferences",
|
|
98
|
+
searchPlaceholder: "Enter a keyword or description",
|
|
99
|
+
searchButton: "Search",
|
|
100
|
+
priceRange: "Price Range",
|
|
101
|
+
wineColor: "Wine Color",
|
|
102
|
+
intensity: "Intensity",
|
|
103
|
+
red: "Red",
|
|
104
|
+
white: "White",
|
|
105
|
+
rose: "Rosé",
|
|
106
|
+
light: "Light",
|
|
107
|
+
medium: "Medium",
|
|
108
|
+
full: "Full"
|
|
70
109
|
},
|
|
71
110
|
de: {
|
|
72
111
|
welcomeMessage: "Was möchten Sie essen? Beschreiben Sie Ihr Gericht und ich empfehle Ihnen den perfekten Wein dazu.",
|
|
@@ -87,7 +126,20 @@ class Translator {
|
|
|
87
126
|
moreInfo: "Mehr Info",
|
|
88
127
|
winePairingIntro: "Für diesen Wein gibt es folgende Essensvorschläge:",
|
|
89
128
|
askForDinner: "Was möchten Sie zum Abendessen essen?",
|
|
90
|
-
clearChatButton: "Chat löschen"
|
|
129
|
+
clearChatButton: "Chat löschen",
|
|
130
|
+
widgetTitle: "Finden Sie Ihren Wein",
|
|
131
|
+
widgetSubtitle: "Suchen Sie nach Ihren Vorlieben",
|
|
132
|
+
searchPlaceholder: "Geben Sie ein Stichwort oder eine Beschreibung ein",
|
|
133
|
+
searchButton: "Suche",
|
|
134
|
+
priceRange: "Preisspanne",
|
|
135
|
+
wineColor: "Weinfarbe",
|
|
136
|
+
intensity: "Intensität",
|
|
137
|
+
red: "Rot",
|
|
138
|
+
white: "Weiß",
|
|
139
|
+
rose: "Rosé",
|
|
140
|
+
light: "Leicht",
|
|
141
|
+
medium: "Mittel",
|
|
142
|
+
full: "Voll"
|
|
91
143
|
}
|
|
92
144
|
};
|
|
93
145
|
}
|