@alexsab-ru/scripts 0.5.5 → 0.6.0

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.
Files changed (3) hide show
  1. package/lib/cookie.js +1 -1
  2. package/lib/form.js +181 -121
  3. package/package.json +1 -1
package/lib/cookie.js CHANGED
@@ -28,7 +28,7 @@ export function setCookie(name, value, props)
28
28
 
29
29
  export function deleteCookie(name)
30
30
  {
31
- setCookie(name, null, { 'domain':settings.domain,'path':'/','expires': -1 })
31
+ setCookie(name, null, { 'domain':window.location.hostname,'path':'/','expires': -1 })
32
32
  }
33
33
 
34
34
  export function cookiecook(days = 90)
package/lib/form.js CHANGED
@@ -1,8 +1,7 @@
1
- import { getCookie } from './cookie';
1
+ import { getCookie, setCookie, deleteCookie } from './cookie';
2
2
  import { createRequest } from './calltouch';
3
3
  import { reachGoal, getFormDataObject } from './analytics';
4
4
 
5
-
6
5
  export const noValidPhone = (phoneValue) => {
7
6
  return ([...new Set(phoneValue.replace(/^(\+7)/g, "").replace(/\D/g, ""))].length === 1);
8
7
  };
@@ -119,145 +118,206 @@ const showMessageModal = (messageModal, icon, message) => {
119
118
  messageModal.classList.remove("hidden");
120
119
  };
121
120
 
122
- export const connectForms = (url, callback, callback_error, ct_routeKey = '', verbose = false) => {
121
+ const propsParams = {
122
+ callback: null,
123
+ callback_error: null,
124
+ ct_routeKey: '',
125
+ confirmModalText: '',
126
+ verbose: false,
127
+ }
123
128
 
124
- // Отправка всех форм
125
- document.querySelectorAll("form").forEach((form) => {
129
+ export const connectForms = (url, props = propsParams) => {
130
+ props = {...propsParams, ...props};
131
+
132
+ async function submitForm(form){
126
133
  const btn = form.querySelector('[type="submit"]');
127
- form.onsubmit = async (event) => {
128
- event.preventDefault();
129
- stateBtn(btn, "Отправляем...", true);
134
+ stateBtn(btn, "Отправляем...", true);
135
+ const agree = form.querySelector('[name="agree"]');
136
+ const phone = form.querySelector('[name="phone"]');
137
+ const errorIcon =
138
+ '<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"><path fill="#ed1c24" d="M26,0A26,26,0,1,0,52,26,26,26,0,0,0,26,0Zm9.6,17.5a1.94,1.94,0,0,1,2,2,2,2,0,1,1-2-2Zm-19.2,0a1.94,1.94,0,0,1,2,2,2,2,0,1,1-2-2ZM39.65,40.69a.93.93,0,0,1-.45.11,1,1,0,0,1-.89-.55,13.81,13.81,0,0,0-24.62,0,1,1,0,1,1-1.78-.9,15.8,15.8,0,0,1,28.18,0A1,1,0,0,1,39.65,40.69Z"></path></svg>';
139
+ const successIcon =
140
+ '<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"><path fill="#279548" d="M26,0A26,26,0,1,0,52,26,26,26,0,0,0,26,0Zm9.6,17.5a1.94,1.94,0,0,1,2,2,2,2,0,1,1-2-2Zm-19.2,0a2,2,0,1,1-2,2A2,2,0,0,1,16.4,17.5ZM40.09,32.15a15.8,15.8,0,0,1-28.18,0,1,1,0,0,1,1.78-.9,13.81,13.81,0,0,0,24.62,0,1,1,0,1,1,1.78.9Z"></path></svg>';
141
+ const errorText =
142
+ '<b class="text-bold block text-2xl mb-4">Упс!</b> Что-то пошло не так. Перезагрузите страницу и попробуйте снова. ';
143
+ const successText = '<b class="text-bold block text-2xl mb-4">Спасибо!</b> В скором времени мы свяжемся с Вами!';
144
+ const messageModal = document.getElementById("message-modal");
130
145
 
131
- const agree = form.querySelector('[name="agree"]');
132
- const phone = form.querySelector('[name="phone"]');
133
- const errorIcon =
134
- '<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"><path fill="#ed1c24" d="M26,0A26,26,0,1,0,52,26,26,26,0,0,0,26,0Zm9.6,17.5a1.94,1.94,0,0,1,2,2,2,2,0,1,1-2-2Zm-19.2,0a1.94,1.94,0,0,1,2,2,2,2,0,1,1-2-2ZM39.65,40.69a.93.93,0,0,1-.45.11,1,1,0,0,1-.89-.55,13.81,13.81,0,0,0-24.62,0,1,1,0,1,1-1.78-.9,15.8,15.8,0,0,1,28.18,0A1,1,0,0,1,39.65,40.69Z"></path></svg>';
135
- const successIcon =
136
- '<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"><path fill="#279548" d="M26,0A26,26,0,1,0,52,26,26,26,0,0,0,26,0Zm9.6,17.5a1.94,1.94,0,0,1,2,2,2,2,0,1,1-2-2Zm-19.2,0a2,2,0,1,1-2,2A2,2,0,0,1,16.4,17.5ZM40.09,32.15a15.8,15.8,0,0,1-28.18,0,1,1,0,0,1,1.78-.9,13.81,13.81,0,0,0,24.62,0,1,1,0,1,1,1.78.9Z"></path></svg>';
137
- const errorText =
138
- '<b class="text-bold block text-2xl mb-4">Упс!</b> Что-то пошло не так. Перезагрузите страницу и попробуйте снова. ';
139
- const successText = '<b class="text-bold block text-2xl mb-4">Спасибо!</b> В скором времени мы свяжемся с Вами!';
140
- const messageModal = document.getElementById("message-modal");
146
+ if (!phoneChecker(phone)) {
147
+ return;
148
+ }
141
149
 
142
- if (!phoneChecker(phone)) {
143
- return;
144
- }
150
+ // если флажок не установлен - фронт
151
+ if (!agree.checked) {
152
+ showErrorMes(form, ".agree", "Чтобы продолжить, установите флажок");
153
+ stateBtn(btn, "Отправить");
154
+ return;
155
+ }
145
156
 
146
- // если флажок не установлен - фронт
147
- if (!agree.checked) {
148
- showErrorMes(form, ".agree", "Чтобы продолжить, установите флажок");
149
- stateBtn(btn, "Отправить");
150
- return;
151
- }
152
- // Отпрвка цели что форма submit только после всех проверок
153
- reachGoal("form_submit");
157
+ // Отпрвка цели что форма submit только после всех проверок
158
+ reachGoal("form_submit");
159
+
160
+ let formData = new FormData(form);
161
+ if(getCookie('fta')) {
162
+ formData.append("fta", true);
163
+ }
164
+ if(getCookie('__gtm_campaign_url')) {
165
+ let source = new URL(getCookie('__gtm_campaign_url'));
166
+ source.search.slice(1).split("&").forEach(function(pair) {
167
+ let param = pair.split("=");
168
+ formData.append(param[0], param[1]);
169
+ });
170
+ }
171
+ formData.append(
172
+ "page_url",
173
+ window.location.origin + window.location.pathname
174
+ );
175
+
176
+ if(typeof window.re != 'undefined') {
177
+ formData.append("re", window.re);
178
+ }
179
+
180
+ window.location.search
181
+ .slice(1)
182
+ .split("&")
183
+ .forEach(function (pair) {
184
+ let param = pair.split("=");
185
+ if(formData.get(param[0])){
186
+ formData.set(param[0], decodeURIComponent(param[1]));
187
+ } else {
188
+ formData.append(param[0], decodeURIComponent(param[1]));
189
+ }
190
+ });
154
191
 
155
- let formData = new FormData(form);
156
- if(getCookie('fta')) {
157
- formData.append("fta", true);
192
+ let formDataObj = {};
193
+ try {
194
+ // Отправка заявки на обратный возов в CallTouch
195
+ if(props.ct_routeKey != '') {
196
+ const requestData = await createRequest(props.ct_routeKey, phone.value, props.verbose);
197
+ formData.append("ct_callback", true);
198
+ formData.append("ctw_createRequest", JSON.stringify(requestData));
199
+ } else {
200
+ throw new Error('Empty ct_routeKey');
158
201
  }
159
- if(getCookie('__gtm_campaign_url')) {
160
- let source = new URL(getCookie('__gtm_campaign_url'));
161
- source.search.slice(1).split("&").forEach(function(pair) {
162
- let param = pair.split("=");
163
- formData.append(param[0], param[1]);
164
- });
202
+ } catch (error) {
203
+ if(props.ct_routeKey != '') {
204
+ formData.append("ctw_createRequest", error);
165
205
  }
166
- formData.append(
167
- "page_url",
168
- window.location.origin + window.location.pathname
169
- );
206
+ props.verbose && console.error("Error during request Calltouch callback:", error);
207
+ formDataObj = getFormDataObject(formData, form.id);
208
+ }
170
209
 
171
- if(typeof window.re != 'undefined') {
172
- formData.append("re", window.re);
173
- }
210
+ const params = new URLSearchParams([...formData]);
174
211
 
175
- window.location.search
176
- .slice(1)
177
- .split("&")
178
- .forEach(function (pair) {
179
- let param = pair.split("=");
180
- if(formData.get(param[0])){
181
- formData.set(param[0], decodeURIComponent(param[1]));
182
- } else {
183
- formData.append(param[0], decodeURIComponent(param[1]));
184
- }
185
- });
212
+ await fetch(url, {
213
+ method: "POST",
214
+ mode: "cors",
215
+ cache: "no-cache",
216
+ credentials: "same-origin",
217
+ headers: {
218
+ "Content-Type": "application/x-www-form-urlencoded",
219
+ },
220
+ body: params,
221
+ })
222
+ .then((res) => res.json())
223
+ .then((data) => {
224
+ props.verbose && console.log(data);
225
+ stateBtn(btn, "Отправить");
226
+ if (data.answer == "required") {
227
+ reachGoal("form_required");
228
+ showErrorMes(form, data.field, data.message);
229
+ return;
230
+ } else if (data.answer == "error") {
231
+ reachGoal("form_error");
186
232
 
187
- let formDataObj = {};
188
- try {
189
- // Отправка заявки на обратный возов в CallTouch
190
- if(ct_routeKey != '') {
191
- const requestData = await createRequest(ct_routeKey, phone.value, verbose);
192
- formData.append("ct_callback", true);
193
- formData.append("ctw_createRequest", JSON.stringify(requestData));
233
+ // Вызов callback_error при ошибке
234
+ if (props.callback_error && typeof props.callback_error === 'function') {
235
+ props.callback_error();
236
+ } else if (messageModal) {
237
+ setCookie('SEND_MAIL', true, {'domain': window.location.hostname,'path':'/','expires':600});
238
+ showMessageModal(messageModal, errorIcon, errorText + "<br>" + data.error);
239
+ }
240
+ return;
194
241
  } else {
195
- throw new Error('Empty ct_routeKey');
242
+ reachGoal("form_success", formDataObj);
243
+
244
+ // Вызов callback при успехе
245
+ if (props.callback && typeof props.callback === 'function') {
246
+ props.callback();
247
+ } else if (messageModal) {
248
+ setCookie('SEND_MAIL', true, {'domain': window.location.hostname,'path':'/','expires':600});
249
+ showMessageModal(messageModal, successIcon, successText);
250
+ }
196
251
  }
197
- } catch (error) {
198
- if(ct_routeKey != '') {
199
- formData.append("ctw_createRequest", error);
252
+ form.reset();
253
+ })
254
+ .catch((error) => {
255
+ reachGoal("form_error");
256
+ console.error("Ошибка отправки данных формы: " + error);
257
+ deleteCookie('SEND_MAIL');
258
+ // Вызов callback_error при ошибке
259
+ if (props.callback_error && typeof props.callback_error === 'function') {
260
+ props.callback_error();
261
+ } else if (messageModal) {
262
+ showMessageModal(messageModal, errorIcon, errorText + "<br>" + error);
200
263
  }
201
- verbose && console.error("Error during request Calltouch callback:", error);
202
- formDataObj = getFormDataObject(formData, form.id);
203
- }
264
+ stateBtn(btn, "Отправить");
265
+ });
266
+ return false;
267
+ }
204
268
 
205
- const params = new URLSearchParams([...formData]);
269
+ async function sendForm(form) {
270
+ if (getCookie('SEND_MAIL')) {
271
+ const confirmModal = document.getElementById('confirm-modal');
272
+ if (confirmModal) {
273
+ confirmModal.querySelector('p').innerHTML = props.confirmModalText || '<span style="color: tomato; font-weight: bold">ПЕРЕДАЙ ТЕКСТ В ОБЪЕКТЕ <br><pre style="color: black; font-weight: 400">props = {confirmModalText: <i>"text"</i>}</pre></span>';
274
+ confirmModal.classList.remove("hidden");
206
275
 
207
- await fetch(url, {
208
- method: "POST",
209
- mode: "cors",
210
- cache: "no-cache",
211
- credentials: "same-origin",
212
- headers: {
213
- "Content-Type": "application/x-www-form-urlencoded",
214
- },
215
- body: params,
216
- })
217
- .then((res) => res.json())
218
- .then((data) => {
219
- verbose && console.log(data);
220
- stateBtn(btn, "Отправить");
221
- if (data.answer == "required") {
222
- reachGoal("form_required");
223
- showErrorMes(form, data.field, data.message);
224
- return;
225
- } else if (data.answer == "error") {
226
- reachGoal("form_error");
276
+ const accept = confirmModal.querySelector('#accept-confirm');
277
+ const acceptClose = confirmModal.querySelector('#accept-close');
227
278
 
228
- // Вызов callback_error при ошибке
229
- if (callback_error && typeof callback_error === 'function') {
230
- callback_error();
231
- } else if (messageModal) {
232
- showMessageModal(messageModal, errorIcon, errorText + "<br>" + data.error);
233
- }
279
+ // Проверка на уже добавленный обработчик
280
+ if (!accept.dataset.listenerAdded) {
281
+ accept.dataset.listenerAdded = 'true';
282
+ accept.addEventListener('click', async () => {
283
+ // Закрываем модальное окно
284
+ confirmModal.classList.add("hidden");
285
+ // Удаляем куку
286
+ deleteCookie('SEND_MAIL');
287
+ // Повторно отправляем форму
288
+ await submitForm(form);
234
289
  return;
235
- } else {
236
- reachGoal("form_success", formDataObj);
290
+ });
291
+ }
237
292
 
238
- // Вызов callback при успехе
239
- if (callback && typeof callback === 'function') {
240
- callback();
241
- } else if (messageModal) {
242
- showMessageModal(messageModal, successIcon, successText);
293
+ // Проверка на уже добавленный обработчик
294
+ if (!acceptClose.dataset.listenerAdded) {
295
+ acceptClose.dataset.listenerAdded = 'true';
296
+ acceptClose.addEventListener('click', () => {
297
+ // Закрываем модальное окно
298
+ const modals = document.querySelectorAll('.modal-overlay');
299
+ form.reset();
300
+ if (modals.length) {
301
+ modals.forEach((modal) => modal.classList.add("hidden"));
243
302
  }
244
- }
245
- form.reset();
246
- })
247
- .catch((error) => {
248
- reachGoal("form_error");
249
- console.error("Ошибка отправки данных формы: " + error);
303
+ confirmModal.classList.add("hidden");
304
+ return;
305
+ });
306
+ }
307
+ return;
308
+ }
309
+ }else{
310
+ // Если куки нет, просто отправляем форму
311
+ await submitForm(form);
312
+ return;
313
+ }
314
+ }
250
315
 
251
- // Вызов callback_error при ошибке
252
- if (callback_error && typeof callback_error === 'function') {
253
- callback_error();
254
- } else if (messageModal) {
255
- showMessageModal(messageModal, errorIcon, errorText + "<br>" + error);
256
- }
257
- stateBtn(btn, "Отправить");
258
- });
259
- return false;
260
- };
316
+ // Отправка всех форм
317
+ document.querySelectorAll("form").forEach((form) => {
318
+ form.addEventListener('submit', async (event) => {
319
+ event.preventDefault();
320
+ await sendForm(form);
321
+ })
261
322
  });
262
-
263
323
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexsab-ru/scripts",
3
- "version": "0.5.5",
3
+ "version": "0.6.0",
4
4
  "description": "common libs for websites",
5
5
  "main": "index.js",
6
6
  "scripts": {