wineater-bot 3.0.5 → 3.0.7

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/index.html CHANGED
@@ -4,9 +4,9 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Chatbot</title>
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: 'HeUw6IXuhvz6tRuXdPEGEbj3SGQ3Q2YtEc1Z8jd41Kg9LtyPb4Epu0to31SYIadG', position: 'right-center', TYPE: 'widget'};</script>
9
- <script type="module" src="./dist/wineater-chatbot.umd.js"></script>
7
+ <!-- <script type="module" src="./dist/wineater-chatbot.umd.js"></script> -->
8
+ <script>window.wineaterData = {CLIENT_TOKEN: 'HeUw6IXuhvz6tRuXdPEGEbj3SGQ3Q2YtEc1Z8jd41Kg9LtyPb4Epu0to31SYIadG', position: 'right-center', TYPE: 'widget', WIDGET_TYPE: 'bar'};</script>
9
+ <script type="module" src="./src/index.js"></script>
10
10
  </head>
11
11
  <body style="margin: 0;">
12
12
  <div id="wineater-widget-conteiner"></div> <!-- Контейнер для виджета -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wineater-bot",
3
- "version": "3.0.5",
3
+ "version": "3.0.7",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "src/index.js",
@@ -0,0 +1,54 @@
1
+ // barConfig.js
2
+
3
+ export const barConfig = {
4
+ barName: "LENEZ",
5
+ dishGroups: [
6
+ {
7
+ groupTitle: "Entradas",
8
+ dishes: [
9
+ "Pimientos rojo asado y aceite de oliva con ajo confitado",
10
+ "Ensalada de arúgula y parmesano",
11
+ "Tomate hierloom aliñado",
12
+ "Aceitunas LENEZ",
13
+ "PapaBnaz",
14
+ "Croquetas | hongos de temporada | jamón serrano",
15
+ "Carpaccio Cesar",
16
+ "Torreznos",
17
+ "Calamares fritos"
18
+ ]
19
+ },
20
+ {
21
+ groupTitle: "Bocadillos",
22
+ dishes: [
23
+ "Brioche de pollo frito, col y salsa macha",
24
+ "Baguette de calamares rebozados en salsa brava",
25
+ "Hogaza de cola de res en recado negro y cebollas encurtidas"
26
+ ]
27
+ },
28
+ {
29
+ groupTitle: "Embutidos",
30
+ dishes: [
31
+ "Jamón Ibérico de bellota",
32
+ "Lomo ibérico",
33
+ "Chorizo ibérico",
34
+ "Plato mixto"
35
+ ]
36
+ },
37
+ {
38
+ groupTitle: "Quesos",
39
+ dishes: [
40
+ "Selección de quesos"
41
+ ]
42
+ },
43
+ {
44
+ groupTitle: "Postres",
45
+ dishes: [
46
+ "Ate con queso manchego semi curado",
47
+ "Gelato de nata con balsámico",
48
+ "Gelato de ron con pasas y “El candado”, Valdespino PX",
49
+ "Gelato Dua Lipa",
50
+ "Créme Brûlée al Orange"
51
+ ]
52
+ }
53
+ ]
54
+ };
package/src/js/i18n.js CHANGED
@@ -37,7 +37,15 @@ class Translator {
37
37
  rose: "Rosé",
38
38
  light: "Léger",
39
39
  medium: "Moyen",
40
- full: "Puissant"
40
+ full: "Puissant",
41
+
42
+ /* -- Новые ключи для bar-режима -- */
43
+ barTitle: "Sélection du bar",
44
+ barSubtitle: "Choisissez vos plats ci-dessous et cliquez sur «Envoyer»",
45
+ barSendButton: "Envoyer",
46
+ barResetButton: "Réinitialiser",
47
+ barName: "Nom du bar",
48
+ barNotesPlaceholder: "Entrez vos souhaits ici...",
41
49
  },
42
50
  es: {
43
51
  welcomeMessage: "¿Qué vas a comer? Cuéntame tu plato y te recomendaré el maridaje perfecto.",
@@ -71,7 +79,15 @@ class Translator {
71
79
  rose: "Rosado",
72
80
  light: "Ligero",
73
81
  medium: "Medio",
74
- full: "Intenso"
82
+ full: "Intenso",
83
+
84
+ /* -- Новые ключи bar -- */
85
+ barTitle: "Platos de Bar",
86
+ barSubtitle: "Selecciona de la lista y presiona «Enviar»",
87
+ barSendButton: "Enviar",
88
+ barResetButton: "Reiniciar",
89
+ barName: "Nombre del bar",
90
+ barNotesPlaceholder: "Agrega tus comentarios aquí...",
75
91
  },
76
92
  en: {
77
93
  welcomeMessage: "What are you planning to eat? Share your dish and I'll recommend the perfect wine pairing for your meal.",
@@ -105,7 +121,15 @@ class Translator {
105
121
  rose: "Rosé",
106
122
  light: "Light",
107
123
  medium: "Medium",
108
- full: "Full"
124
+ full: "Full",
125
+
126
+ /* -- Новые ключи bar -- */
127
+ barTitle: "Bar Dishes",
128
+ barSubtitle: "Select dishes below and click ‘Send’",
129
+ barSendButton: "Send",
130
+ barResetButton: "Reset",
131
+ barName: "Bar Name",
132
+ barNotesPlaceholder: "Add your wishes here...",
109
133
  },
110
134
  de: {
111
135
  welcomeMessage: "Was möchten Sie essen? Beschreiben Sie Ihr Gericht und ich empfehle Ihnen den perfekten Wein dazu.",
@@ -139,21 +163,25 @@ class Translator {
139
163
  rose: "Rosé",
140
164
  light: "Leicht",
141
165
  medium: "Mittel",
142
- full: "Voll"
143
- }
166
+ full: "Voll",
167
+
168
+ /* -- Новые ключи bar -- */
169
+ barTitle: "Bar-Auswahl",
170
+ barSubtitle: "Wählen Sie Ihre Gerichte und klicken Sie auf „Senden“",
171
+ barSendButton: "Senden",
172
+ barResetButton: "Zurücksetzen",
173
+ barName: "Name der Bar",
174
+ }
144
175
  };
145
176
  }
146
177
 
147
178
  async fetchConfig(storeName) {
148
- console.log(storeName);
149
179
  try {
150
180
  const config = await this.api.getStoreConfig(storeName);
151
- console.log(config);
152
181
  this.language = config.lang;
153
182
  } catch (e) {
154
183
  this.language = 'en'; // Fallback to English
155
184
  }
156
- console.log(this.language);
157
185
  }
158
186
 
159
187
  translate(key) {
@@ -161,4 +189,4 @@ class Translator {
161
189
  }
162
190
  }
163
191
 
164
- export default new Translator();
192
+ export default new Translator();
@@ -13,6 +13,7 @@ const widgetStyles = `
13
13
  z-index: 10000;
14
14
  max-width: 1200px;
15
15
  min-width: 1200px;
16
+ min-height: 500px;
16
17
  margin: 40px auto;
17
18
  }
18
19
 
@@ -313,6 +314,95 @@ const widgetStyles = `
313
314
  max-width: 100px;
314
315
  }
315
316
  }
317
+
318
+ /* --- Стили для бар-версии --- */
319
+
320
+ /* Сетка для блюд бара */
321
+ .dish-grid {
322
+ display: grid;
323
+ grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
324
+ gap: 12px;
325
+ margin: 16px 0;
326
+ }
327
+
328
+ /* Отдельная плитка блюда */
329
+ .dish-tile {
330
+ display: flex;
331
+ justify-content: center;
332
+ align-items: center;
333
+ padding: 16px;
334
+ font-size: 14px;
335
+ font-weight: 500;
336
+ border: 1px solid #ccc;
337
+ border-radius: 8px;
338
+ background-color: #fff;
339
+ cursor: pointer;
340
+ user-select: none;
341
+ transition: all 0.2s ease;
342
+ }
343
+
344
+ .dish-tile:hover {
345
+ transform: scale(1.05);
346
+ box-shadow: 0 4px 8px rgba(123, 43, 235, 0.15);
347
+ }
348
+
349
+ .dish-tile.selected {
350
+ background: linear-gradient(90deg, #7B2BEB, #0044FF);
351
+ color: #fff;
352
+ }
353
+
354
+ /* Кнопка "Отправить" для бар-версии */
355
+
356
+ #bar-controls {
357
+ display: flex;
358
+ align-items: stretch; /* или center, если нужно выравнивать */
359
+ gap: 8px;
360
+ margin-top: 16px;
361
+ }
362
+
363
+ /* Задаем одной высотой и одинаковыми отступами */
364
+ #bar-controls input,
365
+ #bar-controls button {
366
+ height: 44px; /* или 48px, как вам нравится */
367
+ line-height: 44px; /* чтобы текст по вертикали выровнялся */
368
+ box-sizing: border-box; /* подстраховка, чтобы высота учитывала бордер */
369
+ }
370
+
371
+ /* Чтобы кнопка и инпут смотрелись схоже по высоте */
372
+ #bar-notes-input {
373
+ flex: 1;
374
+ padding: 0 12px; /* уберите или уменьшите вертикальные padding’и */
375
+ border: 1px solid #ccc;
376
+ border-radius: 6px;
377
+ font-size: 14px;
378
+ outline: none;
379
+ }
380
+
381
+ /* Кнопки – чуть меняем паддинги, чтобы не «лезли» за высоту */
382
+ #bar-send-button,
383
+ #bar-reset-button {
384
+ padding: 0 20px; /* а по вертикали пусть высота сама регулируется через height */
385
+ border-radius: 6px;
386
+ background: linear-gradient(90deg, #7B2BEB, #0044FF);
387
+ font-size: 14px;
388
+ cursor: pointer;
389
+ white-space: nowrap;
390
+ color: white;
391
+ border: none;
392
+ }
393
+
394
+ /* При желании hover-эффект сохранить: */
395
+ #bar-send-button:hover,
396
+ #bar-reset-button:hover {
397
+ transform: scale(1.05);
398
+ box-shadow: 0 4px 8px rgba(123, 43, 235, 0.15);
399
+ }
400
+
401
+
402
+
403
+ .hidden {
404
+ display: none;
405
+ }
316
406
  `;
317
407
 
318
408
  const style = document.createElement('style');
package/src/js/widget.js CHANGED
@@ -2,21 +2,42 @@
2
2
  import './widget-styles.js';
3
3
  import { Api } from './api.js';
4
4
  import translator from './i18n.js';
5
+ import { barConfig } from './barConfig.js';
5
6
 
6
7
  export class WineWidget {
7
8
  constructor() {
8
- this.api = new Api(); // Подключаем API
9
+ // Определяем тип виджета: 'store' (старый) или 'bar' (новый)
10
+ this.widgetType = window?.wineaterData?.WIDGET_TYPE || 'bar';
11
+ this.api = new Api();
12
+
13
+ // Фильтры для store
9
14
  this.selectedFilters = {
10
15
  price: null,
11
16
  color: null,
12
17
  intensity: null,
13
18
  };
19
+
20
+ // Если bar — берем название и список блюд из barConfig
21
+ if (this.widgetType === 'bar') {
22
+ this.barName = barConfig.barName; // "LENEZ"
23
+ this.barDishes = barConfig.dishes; // Список блюд из barConfig
24
+ } else {
25
+ this.barName = '';
26
+ this.barDishes = [];
27
+ }
28
+
29
+ // Инициализируем виджет
14
30
  this.initializeWidget();
15
- this.loadInstantRecommendations(); // Загружаем мгновенные рекомендации
31
+
32
+ // Если нужна мгновенная загрузка рекомендаций только в store
33
+ if (this.widgetType === 'store') {
34
+ this.loadInstantRecommendations();
35
+ }
16
36
  }
17
37
 
18
38
  initializeWidget() {
19
39
  const widgetContainer = document.getElementById('wineater-widget-conteiner');
40
+ if (this.widgetType === 'store') {
20
41
  const widgetHTML = `
21
42
  <div id="wine-widget-container">
22
43
  <div id="wine-widget-left">
@@ -75,20 +96,77 @@ export class WineWidget {
75
96
  </div>
76
97
  `;
77
98
  widgetContainer.insertAdjacentHTML('beforeend', widgetHTML);
78
- this.addEventListeners();
99
+ this.addEventListenersStoreVersion();
100
+ } else {
101
+ const barHTML = `
102
+ <div id="wine-widget-container">
103
+ <div id="wine-widget-right">
104
+ ${barConfig.dishGroups.map(group => `
105
+ <!-- Обёртка группы -->
106
+ <div class="dish-group">
107
+ <!-- Заголовок группы, если нужен -->
108
+ <!-- Сетка блюд конкретной группы -->
109
+ <div class="dish-grid">
110
+ ${group.dishes.map(dish => `
111
+ <div class="dish-tile" data-dish="${dish}">
112
+ ${dish}
113
+ </div>
114
+ `).join('')}
115
+ </div>
116
+ </div>
117
+ `).join('')}
118
+
119
+ <div id="wine-placeholder"></div>
120
+
121
+ <div id="loading-indicator" class="hidden">
122
+ <div id="typing-indicator" class="typing-indicator">
123
+ <span></span><span></span><span></span>
124
+ </div>
125
+ </div>
126
+
127
+ <!-- Кнопки для отправки и сброса -->
128
+ <div id="bar-controls">
129
+ <input
130
+ type="text"
131
+ id="bar-notes-input"
132
+ placeholder="${translator.translate('barNotesPlaceholder')}"
133
+ />
134
+ <button id="bar-send-button">
135
+ ${translator.translate('barSendButton')}
136
+ </button>
137
+ <button id="bar-reset-button" class="hidden">
138
+ ${translator.translate('barResetButton')}
139
+ </button>
140
+ </div>
141
+
142
+ </div>
143
+ </div>
144
+ `;
145
+ widgetContainer.insertAdjacentHTML('beforeend', barHTML);
146
+
147
+ // Привязка обработчиков "плиток" и кнопки
148
+ this.addEventListenersBarVersion();
149
+ }
79
150
  }
80
151
 
81
- addEventListeners() {
82
- document.getElementById('wine-search-button').addEventListener('click', () => this.handleSearch());
152
+ addEventListenersStoreVersion() {
153
+ document
154
+ .getElementById('wine-search-button')
155
+ .addEventListener('click', () => this.handleSearch());
156
+
157
+ // Привязка фильтров
83
158
  this.setupFilterButtons('price-buttons', 'price');
84
159
  this.setupFilterButtons('color-buttons', 'color');
85
160
  this.setupFilterButtons('intensity-buttons', 'intensity');
86
- // Добавляем обработчик нажатия Enter для поля ввода
87
- document.getElementById('wine-search-input').addEventListener('keydown', (event) => {
88
- if (event.key === 'Enter') {
89
- this.handleSearch();
90
- }
91
- });
161
+
162
+ // Обработчик Enter в поле ввода
163
+ document
164
+ .getElementById('wine-search-input')
165
+ .addEventListener('keydown', (event) => {
166
+ if (event.key === 'Enter') {
167
+ this.handleSearch();
168
+ }
169
+ });
92
170
  }
93
171
 
94
172
  setupFilterButtons(containerId, filterKey) {
@@ -236,4 +314,98 @@ export class WineWidget {
236
314
  console.error('Error loading instant recommendations:', error.message);
237
315
  }
238
316
  }
317
+ addEventListenersBarVersion() {
318
+ // Теперь плитки блюд появятся только после renderDishGroups()
319
+ const tileElements = document.querySelectorAll('.dish-tile');
320
+ tileElements.forEach(tile => {
321
+ tile.addEventListener('click', () => {
322
+ tile.classList.toggle('selected');
323
+ });
324
+ });
325
+
326
+ // Собираем все группы (или все .dish-grid)
327
+ const dishGroups = document.querySelectorAll('.dish-group');
328
+
329
+ // Находим элементы управления
330
+ const sendButton = document.getElementById('bar-send-button');
331
+ const resetButton = document.getElementById('bar-reset-button');
332
+ const notesInput = document.getElementById('bar-notes-input');
333
+ const winePlaceholder = document.getElementById('wine-placeholder');
334
+
335
+ if (!sendButton || !resetButton || !notesInput || !winePlaceholder) return;
336
+
337
+ // Нажатие "Отправить"
338
+ sendButton.addEventListener('click', async () => {
339
+ dishGroups.forEach(g => g.classList.add('hidden'));
340
+ this.showLoadingIndicator();
341
+
342
+ // 1) Собираем выбранные блюда
343
+ const selectedDishes = [];
344
+ document.querySelectorAll('.dish-tile.selected').forEach(tile => {
345
+ selectedDishes.push(tile.dataset.dish);
346
+ });
347
+
348
+ // 2) Берём пожелания (notes)
349
+ const notes = notesInput.value.trim(); // не стираем и не скрываем поле
350
+
351
+ // 3) Формируем запрос
352
+ const queryParts = [];
353
+ if (selectedDishes.length > 0) {
354
+ queryParts.push(`Dishes: ${selectedDishes.join(', ')}`);
355
+ }
356
+ if (notes) {
357
+ queryParts.push(`Notes: ${notes}`);
358
+ }
359
+ const finalQuery = queryParts.join('; ');
360
+
361
+ console.log('Final query =>', finalQuery);
362
+
363
+ try {
364
+ // 4) Делаете запрос к API
365
+ const results = await this.api.getWineRecommendationsSearch(finalQuery);
366
+
367
+ // 5) Скрываем группы блюд (если хотите, чтобы больше не мешались)
368
+
369
+ // 6) Отображаем результаты
370
+ if (results && results.length > 0) {
371
+ this.displayResults(results, true);
372
+ } else {
373
+ this.displayNoResultsMessage();
374
+ }
375
+
376
+ // 7) Показываем кнопку «Сбросить»
377
+ resetButton.classList.remove('hidden');
378
+
379
+ // 8) Кнопку «Отправить» НЕ скрываем — оставляем!
380
+ // ...никакого sendButton.classList.add('hidden')
381
+ } catch (error) {
382
+ console.error('Error while fetching bar recommendations:', error);
383
+ this.displayErrorMessage();
384
+ } finally {
385
+ this.hideLoadingIndicator();
386
+ }
387
+ });
388
+
389
+ // Нажатие "Сбросить"
390
+ resetButton.addEventListener('click', () => {
391
+ // 1) Показываем все группы (блюда)
392
+ dishGroups.forEach(g => g.classList.remove('hidden'));
393
+
394
+ // 2) Снимаем выделение с плиток
395
+ tileElements.forEach(tile => tile.classList.remove('selected'));
396
+
397
+ // 3) Очищаем результаты
398
+ winePlaceholder.innerHTML = '';
399
+
400
+ // 4) Прячем кнопку «Сбросить»
401
+ resetButton.classList.add('hidden');
402
+
403
+ notesInput.value = '';
404
+
405
+ // 5) Инпут с пожеланиями НЕ трогаем — пусть остается, пользователь может менять
406
+ // notesInput.value = ''; // Если захотите — можете раскомментить, чтобы тоже сбрасывать
407
+
408
+ // 6) «Отправить» и дальше на месте, не меняется
409
+ });
410
+ }
239
411
  }