PageSourceSearch

https://top1like.com/assets/js/js-user.js

js top1like.com collected 2026-10-02 16:44:14 UTC 42,300 bytes, 1,319 lines download raw bytes

1var userInputUID = false,
2  paymentTimeOut = 45,
3  discountCodeMap = {},
4  // Stand for selected discount
5  sDiscount = null;
6
7const multiOrderData = {
8  running: false,
9  uidElementSelector: '#formUserAction [name=uid], #formUserAction [name=link], #formUserAction #url.form-control',
10  customQuantitySelector: '#multi-order-custom-quantity',
11  countSelector: '#count, #vip_package, [name="vip_package"], [name="count"]',
12  purchaseData: [],
13  requestStop: false,
14  idMap: {},
15  orderSubTotal: 0,
16  elementType: '',
17}
18
19$(document).ready(function(){
20  if ($('body').hasClass('test-mode')) {
21    Swal.fire({
22      title: 'Để sử dụng dịch vụ bạn cần đăng ký/ đăng nhập tài khoản cho riêng bạn, tài khoản xem thử này không thể mua!',
23      icon: 'warning',
24      html: '',
25      allowOutsideClick: true,
26      showCancelButton: true,
27      confirmButtonText: 'Tiếp tục xem',
28      cancelButtonText: 'Đăng xuất'
29    }).then(function(data) {
30      if (data && data.isDismissed) {
31        $.get('/logout').done(function() {
32          window.location.href = '/';
33        });
34      }
35    })
36  }
37
38  $('#user_input_uid').click(function() {
39    userInputUID = !userInputUID;
40    $(this).html(userInputUID ? 'Nhập info tự động' : 'Nhập info thủ công');
41    toastr.success("Đã chuyển qua chế độ: " + (userInputUID ? 'Nhập info thủ công' : 'Nhập info tự động'));
42    if (!userInputUID) $('#link').trigger('change');
43  });
44
45  $('.toggle-sidebar-mobile').click(function() {
46    $('#kt_aside_mobile_toggler').trigger('click');
47  });
48
49  getPayment();
50
51  if (typeof type !== 'undefined' && ['video', 'livestream_v2', 'fb_view_100k_reel', 'view_other'].includes(type)) {
52    callAjaxPost('/view/view_available').then(function(data) {
53      Object.keys(data).forEach(function (key) {
54        var selector = `#${key},.${key}`;
55        $(selector).text(data[key]);
56        if (data[key] == 0 && $(selector).parent().hasClass('server-status')) $(selector).parent().addClass('stopped');
57      });
58    })
59  }
60
61 checkDiscount();
62
63  // Check and show modalNotifyByType
64  try {
65    if ($('#modalNotifyByType').length) {
66      if (typeof type === 'undefined') type = 'common';
67
68      $('.btn-hide-type-popup').click(function() {
69        $.cookie('popup_' + type, + new Date());
70      });
71
72      var matchCookie = $.cookie('popup_' + type);
73      if (!matchCookie || moment().diff(moment(Number(matchCookie)), 'hour') >= 5) {
74        $('#modalNotifyByType').modal('show');
75      }
76    }
77  } catch (e) {
78    console.error('modalNotifyByType:', e);
79  }
80
81  $("#service-select").val(window.location.pathname).select2({
82    placeholder: "Chọn dịch vụ",
83    allowClear: true,
84    "language": {
85      "noResults": function(){
86        return "Không có kết quả, liên hệ admin nếu cần bổ sung dịch vụ";
87      }
88    },
89  }).on('select2:select', function () {
90    window.location.href =  $('#service-select').val();
91  });
92
93  if (typeof type !== "undefined" && $(multiOrderData.uidElementSelector).length) {
94    multiOrderData.elementType = $(multiOrderData.uidElementSelector).attr('id');
95
96    if (!$(multiOrderData.countSelector).length) console.error('no count');
97
98    $(multiOrderData.uidElementSelector).after($(
99        `
100            <div class="mt-2" id="custom-quantity-wrapper" style="display: none">
101              <div class="custom-control custom-switch">
102                <input type="checkbox" class="custom-control-input" id="multi-order-custom-quantity">
103                <label class="custom-control-label" for="multi-order-custom-quantity"></label>
104                <label class="text-bold" for="multi-order-custom-quantity">Tùy chỉnh mỗi uid</label>
105              </div>
106              
107              <div class="text-danger">
108                Bạn có thể nhập theo định dạng {Link/UID} | {số lượng} để mua với số lượng tùy chọn theo từng Link / UID<br />
109                VD: 12345 | 30
110              </div>
111              
112              <div id="multi-order-info" >
113                Tổng số dòng điền: <span id="total_order" class="text-danger">0</span> đơn hàng.
114                </div>
115            </div>
116        `
117    ));
118
119    $('#formUserAction').prepend(
120        `
121            <div class="form-group">
122              <div class="custom-control custom-switch">
123                <input type="checkbox" class="custom-control-input" id="switch_multi_order">
124                <label class="custom-control-label" for="switch_multi_order"></label>
125                <label for="switch_multi_order">Mua nhiều đơn cùng lúc</label>
126              </div>
127            </div>
128        `
129    );
130
131    $('#multi-order-custom-quantity').change(function() {
132      const checked = $(this).is(':checked');
133      $('#total').closest('.form-group')[checked ? 'hide' : 'show']();
134      $(multiOrderData.countSelector).closest('.form-group')[checked ? 'hide' : 'show']();
135
136      // trigger change first server
137      $('.servers input[name="server"]:checked').trigger('change');
138    });
139
140    $('body').append(`
141    <div class="modal fade" id="modalMultiOrder" tabindex="-1" role="dialog" aria-hidden="true">
142      <div class="modal-dialog modal-xl" role="document">
143        <div class="modal-content">
144          <div class="modal-header">
145            <h5 class="modal-title">Mua nhiều đơn</h5>
146            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
147              <span aria-hidden="true">×</span>
148            </button>
149          </div>
150          <div class="modal-body">
151            <div class="form-group">
152              <h5>
153                UID/Link: <span class="text-danger" id="multi_order_current_uid"></span>
154              </h5>
155    
156              <h5>Tiến độ: <span class="text-success" id="multi_order_progress"></span></h5>
157            </div>
158    
159            <button class="btn btn-success multi_order_btn_start">Bắt đầu mua</button>
160            <button class="btn btn-danger" id="multi_order_btn_stop">Dừng</button>
161    
162            <hr />
163    
164            <div class="table-responsive">
165              <table class="table table-bordered">
166                <thead>
167                <tr>
168                  <th>UID/Link đã nhập</th>
169                  <th>UID/Link mua</th>
170                  <th>SL</th>
171                  <th>Tổng đơn</th>
172                  <th>Trạng thái</th>
173                </tr>
174                </thead>
175                <tbody></tbody>
176              </table>
177            </div>
178
179            <hr />
180            <button class="btn btn-success multi_order_btn_start">Bắt đầu mua</button>
181          </div>
182          <div class="modal-footer">
183            <button type="button" class="btn btn-secondary" data-dismiss="modal">Đóng</button>
184          </div>
185        </div>
186      </div>
187    </div>
188    `);
189
190    $('.multi_order_btn_start').click(async function() {
191      if (!multiOrderData.purchaseData.length) return;
192      changePurchaseMultiOrderStatus(false);
193
194      const uidElement = $(multiOrderData.uidElementSelector);
195      if (!uidElement.length) return;
196      let errorUid = [];
197
198      const createOrder = async () => {
199        return new Promise((resolve) => {
200          $.ajax({
201            type: "POST",
202            url: $('#formUserAction').attr('action'),
203            data: $('#formUserAction').serialize(),
204            success: function(data) {
205              if (data.status) return resolve([true, data]);
206              return resolve([false, data.msg]);
207            },
208            error: function (xhr) {
209              console.error(xhr);
210              return resolve([false, 'timeout']);
211            }
212          });
213        })
214      }
215
216      const updateProgress = (text) => {
217        $('#multi_order_progress').text(text);
218      }
219
220      $('#modalMultiOrder').modal('show');
221
222      toastr.info('Đang tiến hành mua...');
223
224      let totalOrder = multiOrderData.purchaseData.length;
225      for (let index = 0; index < totalOrder; index++) {
226        if (multiOrderData.requestStop) {
227          multiOrderData.requestStop = false;
228          toastr.error('Đã dừng');
229          updateProgress('Đã dừng');
230          changePurchaseMultiOrderStatus(true);
231
232          return;
233        }
234
235        let purchaseInfo = multiOrderData.purchaseData[index];
236        if (purchaseInfo.errorMsg) {
237          errorUid.push(purchaseInfo.purchaseId || purchaseInfo.originId);
238          continue;
239        }
240        if (purchaseInfo.success) continue; // skip purchased success
241
242        $('#multi_order_current_uid').text(purchaseInfo.purchaseId);
243
244        uidElement.val(purchaseInfo.purchaseId.toString().trim());
245        if (purchaseInfo.purchaseName && $('#name').length) $('#name').val(purchaseInfo.purchaseName);
246        if ($('#formUserAction #url').length) $('#url').val(purchaseInfo.originId);
247
248        $(multiOrderData.countSelector).val(purchaseInfo.quantity);
249        $("#formUserAction [name=force_buff]").val(purchaseInfo.force ? '1' : '');
250
251        updateProgress(`Đang mua ${index + 1}/${totalOrder}`);
252
253        if (index > 0) {
254          if (type === 'like_tiktok' && ['server_3', 'server_5'].includes(selectedServer)) {
255            await wait(selectedServer === 'server_3' ? 4 : 2);
256          } else if (type === 'follow_tiktok' && ['server_6'].includes(selectedServer)) {
257            await wait(3);
258          }
259        }
260
261        let [success, orderData] = await createOrder();
262
263        if (success) {
264          multiOrderData.purchaseData[index].success = true;
265          await wait(0.25);
266        }
267        else {
268          let errorMsg = orderData.toString();
269
270          if (errorMsg.includes('nếu cố tình mua số')) {
271            const confirm = await swalConfirm(`UID: ${purchaseInfo.purchaseId}: ` + errorMsg, 'Tiếp tục mua', 'Hủy mua');
272            if (confirm) {
273              purchaseInfo.force = true;
274              setForceBuff();
275
276              index--;
277              continue;
278            }
279          }
280          else if (errorMsg.includes('Hệ thống bảo trì')) {
281            index--;
282            const confirmed = await swalTimeOut(
283                'Hệ thống đang bảo trì, việc mua đơn sẽ được tiếp tục sau thời gian chờ',
284                'question',
285                45 * 1000,
286                'Vui lòng chờ',
287                'Dừng mua đơn',
288                true);
289
290            if (!confirmed) {
291              multiOrderData.requestStop = true;
292              toastr.success('Đang dừng quá trình mua...');
293            }
294            continue;
295          }
296          else if (errorMsg.includes('ua chậm lại')) {
297            index--;
298            await wait(5, 7);
299            continue;
300          }
301
302          multiOrderData.purchaseData[index].errorMsg = orderData;
303          let errorLine = purchaseInfo.purchaseId;
304          if ($(multiOrderData.customQuantitySelector).is(':checked')) errorLine += ' | ' + purchaseInfo.quantity;
305          errorUid.push(errorLine);
306        }
307
308        mo_showPurchaseInfo();
309      }
310
311      $('#multi_order_current_uid').text('N/A');
312
313      updateProgress(`Mua thành công ${totalOrder - errorUid.length}/${totalOrder}`);
314      toastr.success('Đã mua xong');
315
316      let resetForm = true;
317      if (errorUid.length) {
318        resetForm = false;
319        $('#list_uid').val(errorUid.join("\n"));
320        toastr.warning(`Có ${errorUid.length} đơn lỗi, vui lòng mua lại!`)
321      }
322
323      onCreateOrderSuccess(resetForm);
324
325      $('.multi_order_btn_start').hide();
326      $('#multi_order_btn_stop').hide();
327
328      $('#switch_multi_order').trigger('change');
329    });
330
331    $('#multi_order_btn_stop').click(function() {
332      multiOrderData.requestStop = true;
333      toastr.success('Đang dừng quá trình mua...');
334    });
335
336    $(document).on('change', '#switch_multi_order', function () {
337      $('#total').closest('.form-group').show();
338
339      $("#total")
340          .closest('.form-group')
341          .find('label')
342          .text('Tổng Giá');
343
344      let uidElement = $(multiOrderData.uidElementSelector);
345      if (!uidElement) return console.error('element not found');
346
347      const multiId = $(this).is(':checked');
348
349      const nameElement = $('#formUserAction [name="name"]');
350      if (nameElement.length) nameElement.closest('.form-group')[multiId ? 'hide' : 'show']();
351
352      $('#custom-quantity-wrapper')[multiId ? 'show' : 'hide']();
353
354      if (multiId) {
355        // Append text area if not exist
356        if (!$('#list_uid').length) {
357          $('<textarea class="form-control" id="list_uid" placeholder="Mỗi UID/link 1 hàng" rows="5"></textarea>')
358              .insertAfter(uidElement)
359        }
360
361        let oldValue = uidElement.val();
362        uidElement.prop('required', false).val('').hide();
363        $('#formUserAction #name').prop('required', false);
364
365        $('#list_uid')
366            .prop('required', true)
367            .show();
368
369        if (!$('#list_uid').val()) $('#list_uid').val(oldValue);
370
371        toastr.success('Đã chuyển qua chế độ mua nhiều UID/Link cùng lúc');
372      }
373      else {
374        // back to one uid
375        let currentUid = $('#list_uid').val().split("\n")[0];
376        uidElement
377            .val(currentUid)
378            .prop('required', true)
379            .show();
380        if (currentUid) uidElement.trigger('change');
381
382        $('#formUserAction #name').prop('required', true);
383
384        $('#list_uid')
385            .val('')
386            .prop('required', false)
387            .hide();
388
389        toastr.success('Đã chuyển qua chế độ mua một UID/Link');
390      }
391
392      $('#count').trigger('change');
393    });
394
395    $(document).on('change', '#list_uid', function () {
396      if (typeof selfCalculatorPrice === "function") {
397        selfCalculatorPrice();
398      } else if (type.match(/vip/)) {
399        $('#formUserAction [name=vip_package]').trigger('change');
400      } else {
401        $('#count').trigger('change');
402      }
403      if (typeof calculatorPrice === "function") calculatorPrice();
404    });
405
406    $(document).on('click', '.multi_order_btn_get_uid', async function () {
407      swalLoading('Đang get link...');
408
409      const index = Number($(this).data('index'));
410      let purchaseInfo = await mo_getPurchaseInfo(multiOrderData.purchaseData[index].originId);
411
412      if (purchaseInfo.errorMsg) {
413        multiOrderData.purchaseData[index].errorMsg = purchaseInfo.errorMsg;
414        swalError('Get UID Lỗi: ' + purchaseInfo.errorMsg);
415      } else {
416        multiOrderData.purchaseData[index] = {
417          ...multiOrderData.purchaseData[index],
418          errorMsg: '',
419          uidError: false,
420          purchaseId: purchaseInfo.purchaseId,
421          purchaseName: purchaseInfo.purchaseName,
422        }
423        swalSuccess('Đã get lại UID');
424      }
425
426      mo_showPurchaseInfo();
427    });
428  }
429});
430
431function checkDiscount() {
432  if ($('#discount_code_container').length) {
433    callAjaxPost('/discount_codes').then(async function(res) {
434      if (!res.status || !res.codes.length) {
435        $('#discount_code_container').hide();
436        return;
437      }
438
439      $('#discount_code_container').show();
440      // Reset parameters
441      $('#list_codes').html('');
442      discountCodeMap = {};
443      sDiscount = null;
444      $('#discount-status').attr('class', '').html('');
445
446      res.codes.forEach(row => {
447        discountCodeMap[row.code] = row;
448        $('#list_codes').append(`
449          <div class="code-item" title="Đơn tối thiểu ${formatMoney(row.min_order)}₫, giảm tối đa ${formatMoney(row.max_discount)}, còn ${row.left} lượt">
450            <div class="head">Giảm ${row.discount_percent}%</div>
451            <div class="code-body"><span class="code-content">${row.code}</span><span class="far fa-clipboard"></span></div>
452          </div>
453        `);
454
455        $('.code-item').tooltip();
456      });
457
458      // Bind click events
459      $(document).on('click', '.code-item', function () {
460        var codeText = $(this).find('.code-content').text();
461        var code = discountCodeMap[codeText] || false;
462        if (!code || (sDiscount && code.code === sDiscount.code)) return;
463
464        $('.code-item').removeClass('selected');
465        $(this).addClass('selected');
466
467        $('[name="discount_code"]').val(code.code);
468        sDiscount = code;
469
470        if (['comment', 'review', 'comment_instagram', 'vip_like_instagram', 'bot_comment', 'bot_love_story',
471        'proxy', 'comment_tiktok', 'live_tiktok', 'livestream_v2', 'video', 'view_other', 'vip_cmt', 'vip_like',
472        'vip_live', 'vip_share', 'vip_view_video', 'comment_youtube', 'view_60k_offline', 'view_60k_live'].includes(type)) {
473          try {
474            ['calculatorPrice', 'selfCalculatorPrice'].forEach(functionName => {
475              if (typeof window[functionName] == "function") {
476                window[functionName]();
477                throw new Error('break');
478              }
479            })
480          } catch (e) {}
481        } else {
482          if ($('#count').length) {
483            $('#count').trigger('change');
484          } else {
485            if (['filter_friend'].includes(type)) {
486              let total = applyDiscountAndCurrency($('[name=price]').val());
487              $("#total").val(formatMoney(total, ' VNĐ'));
488            } else {
489              toastr.error('Lỗi mã giảm giá!');
490            }
491          }
492        }
493      });
494    });
495  }
496}
497
498function getPayment() {
499  callAjaxPost('/new_update').then(async function(data) {
500    var payment = data.payment;
501    var refund = data.refund;
502
503    var messages = [];
504    if (payment > 0) {
505  if (window.__BANK_PAYMENT_VERIFYING === true) {
506    window.__BANK_PAYMENT_SUCCESS = true;
507    window.__BANK_PAYMENT_VERIFYING = false;
508
509    try {
510      const bankModalEl = document.getElementById('bankPayModal');
511
512      if (bankModalEl) {
513        const bsModal = bootstrap.Modal.getInstance(bankModalEl) || new bootstrap.Modal(bankModalEl);
514        bsModal.hide();
515      }
516
517      $('.modal-backdrop').remove();
518      $('body').removeClass('modal-open').css('padding-right', '');
519    } catch (e) {}
520
521    Swal.fire({
522      title: 'Thành công',
523      text: `Bạn đã nạp thành công ${formatMoney(payment, ' VND')}, chúc bạn một ngày tốt lành!`,
524      icon: 'success',
525      confirmButtonText: 'OK'
526    }).then(function () {
527      window.location.reload();
528    });
529
530    return;
531  }
532
533  messages.push({
534    must_read: false,
535    text: `Bạn đã nạp thành công ${formatMoney(payment, ' VND')}, chúc bạn một ngày tốt lành!`
536  });
537}
538   if (refund > 0) {
539      let refundNotes = "";
540      if (data.notes && data.notes.length > 0) {
541        refundNotes = data.notes.join("\n- ");
542      }
543    
544      messages.push({
545        must_read: false,
546        text: `
547        ${refundNotes}
548        <br>
549        Số tiền ${formatMoney(refund, ' VND')}
550        <br>Hãy kiểm tra nhật ký hoàn tiền và mua lại ở sever khác`
551      });
552    }
553    if (data.notify) messages.push({must_read: true, text: data.notify});
554    
555    for (var i = 0; i < messages.length; i++) {
556      var item = messages[i];
557      if (item.must_read) {
558        let contentText = item.text;
559        if (contentText.includes('Token api domain con')) contentText += '\nHãy cập nhật token api để website hoạt động';
560        await swalNotifyTimeOut(contentText);
561      }
562      
563      else {
564        
565        await swalSuccess(item.text);
566      }
567    }
568  });
569
570  setTimeout(function() {
571    getPayment();
572  }, 5000);
573}
574
575function getVip(id) {
576  return new Promise(function (resolve, reject) {
577    $.post('/vip/show', {id: id}).done(function(data) {
578      if (!data.status) return reject(false);
579      return resolve(data.vip);
580    });
581  })
582}
583
584$(document).on("click", ".btn-edit-vip", function () {
585  getVip($(this).data('id')).then(function(vip) {
586    $('#modalUpdate input[name="id"]').val(vip.id);
587    if (typeof onEditVip === "function") onEditVip(vip);
588    $('#modalUpdate').modal('show');
589  }).catch(console.error);
590});
591
592var handleVipAction = function(data) {
593  if (data.status) {
594    swalSuccess();
595    reloadTable();
596  } else {
597    swalError(data.msg);
598  }
599};
600
601$(document).on("click", ".btn-refund-vip", async function () {
602  let alertMsg = 'Bạn có chắc chắn hủy với phí 7 ngày?';
603  if (type.match(/twitter/)) alertMsg = 'Hệ thống sẽ xóa uid khỏi website, không hoàn tiền dịch vụ này?';
604
605  if (!await swalConfirm(alertMsg)) return;
606  var that = this;
607  $(this).hide();
608  swalLoading();
609  callAjaxPost('/vip/refund', {id: $(this).data('id')}).then(handleVipAction).finally(function() {
610    $(that).show();
611  })
612});
613
614/**
615 * Handle submit form update service
616 */
617$('#formUpdate').submit(function(e) {
618  e.preventDefault();
619
620  swalLoading();
621  $.ajax({
622    type: "POST",
623    url: $(this).attr("action"),
624    data: $(this).serialize(),
625    success: function (data) {
626      if(data.status === 1) {
627        swalSuccess(data.msg);
628        $('.modal.show').modal('hide');
629      } else {
630        swalError(data.msg);
631      }
632    }
633  });
634});
635
636function onCreateOrderSuccess(resetForm = true) {
637  if (datatableLog || datatableVip || typeof allPrices !== "undefined") {
638    reloadTable();
639    sDiscount = null;
640    checkDiscount();
641
642    if (typeof app === "undefined" && resetForm) {
643      $('#formUserAction').trigger("reset");
644      $('[name="force_buff"]').val('');
645
646      if ($('input[name="server"]').length) {
647        if (!$('.radio-server input[type="radio"][name="server"]:checked').val())
648          $('.radio-server:not(.pause) input[name="server"]').first().prop('checked', true);
649        $('input[name="server"]:checked').trigger('change');
650      }
651
652      // If no server selected, just select first server
653      if ($('input[type="radio"][name="service_id"]').length
654          && !$('.radio-server input[type="radio"][name="service_id"]:checked').val()) {
655        $('.radio-server:not(.pause) input[name="service_id"]')
656            .first()
657            .prop('checked', true)
658            .trigger('change');
659      }
660    }
661
662    if (type === 'livestream_v2') $('[name="server_id"]').trigger('change');
663    if (type === 'bank_voucher') $('[name="bank_id"]').trigger('change');
664    if (typeof selectedServer !== "undefined") $(`input[name="server"][value="${selectedServer}"]`).prop('checked', true).trigger('change');
665  }
666}
667
668function setForceBuff() {
669  const _form = $('#formUserAction');
670
671  let forceBuffElm = _form.find("[name=force_buff]");
672  if (!forceBuffElm.length) _form.append('<input type="hidden" name="force_buff" value="">');
673  _form.find("[name=force_buff]").val('1');
674}
675
676$("#formUserAction").submit(async function (e) {
677  e.preventDefault();
678
679  if (testUser) return swalError('Đây là tài khoản trải nghiệm hãy đăng xuất và đăng ký tài khoản cho riêng bạn');
680
681  if (type === 'tick_youtube') {
682    if (!await swalConfirm('Hãy add email" người quản lý" trước khi oder đơn hàng nhé?')) return;
683  }
684  else if (type === 'like_page' && $('#link').val().match(/^1000/) && selectedServer === 'server_3') {
685    if (!await swalConfirm('Page profile không nên mua server này, tỉ lệ thiếu cao, kbh, bạn có muốn tiếp tục?')) return;
686  }
687
688  if ($('input[name=server]').length && $('input[name="server"]:checked')) {
689    // Check server before submit
690    var parent = $('input[name="server"]:checked').closest('.radio-server');
691    if (parent.hasClass('pause')) return swalError('Server này đang tạm bảo trì. Hãy chọn server khác nhé');
692    if (parent.hasClass('slow') && !await swalConfirm('Server này đang bị chậm. Nếu cần nhanh hãy lựa chọn server khác.', 'Tiếp tục', 'Huỷ')) return;
693  }
694
695  // Format fields
696  var formatFields = ['#name'];
697  formatFields.forEach(function(field) {
698    if (!$(field).length) return;
699    var value = $(field).val();
700    if (value.length > 150) value = value.substr(0, 140);
701    $(field).val(value);
702  });
703
704  // Check live before purchase
705  // if (type === 'live_tiktok') {
706  //   let tiktokLink = $('#formUserAction [name="link"]').val();
707  //
708  //   if (!tiktokLink.includes('/live')) {
709  //     swalLoading('Đang check live...');
710  //     let liveData = await callAjaxPost('/api/check_tiktok_live', {
711  //       link: tiktokLink
712  //     });
713  //
714  //     if (!liveData.status) {
715  //       let confirm = await swalConfirm(liveData.msg);
716  //       if (!confirm) return;
717  //     }
718  //   }
719  // }
720
721  if (typeof selfValidator === "function") {
722    var msg = await selfValidator();
723    if (msg === null) return; // null on silent
724    if (msg !== true) return swalError(msg);
725  }
726
727  if ($('#switch_multi_order').is(':checked')) return preparePurchaseMultiOrder();
728
729  var url = $(this).attr("action");
730  $("#submit").attr("disabled",true);
731  $("#submit").addClass("kt-spinner");
732  $("#submit").addClass("kt-spinner--left");
733  $("#submit").addClass("kt-spinner--md");
734  $("#submit").addClass("kt-spinner--light");
735
736  swalLoading('Đang xử lý, vui lòng chờ');
737
738  $.ajax({
739    type: "POST",
740    url: url,
741    data: $(this).serialize(),
742    success: function(data) {
743      if(data.status === 1) {
744        swalSuccess(data.msg);
745
746        onCreateOrderSuccess();
747
748        $([document.documentElement, document.body]).animate({
749          scrollTop: $("#formUserAction").offset().top - 300
750        }, 500);
751      }
752      else {
753        if (data.msg && data.msg.toString()) {
754          let errorMsg = data.msg.toString();
755
756          if (errorMsg.includes('nhấn "Tiếp tục mua" để thử lại')) {
757            swalConfirm(data.msg, 'Tiếp tục mua').then(function (confirm) {
758              if (confirm) $("#formUserAction").trigger('submit');
759            });
760            return;
761          }
762          else if (errorMsg.includes('nếu cố tình mua số')) {
763            swalConfirm(data.msg, 'Tiếp tục mua', 'Hủy mua').then(function (confirm) {
764              if (confirm) {
765                setForceBuff();
766
767                $('#formUserAction').trigger('submit');
768              }
769            });
770            return;
771          }
772        }
773
774        swalError(data.msg);
775      }
776    },
777    error: function (xhr) {
778      console.error(xhr);
779      swalError('Quá thời gian chờ khi tạo đơn, đơn hàng của bạn đang được xử lý.' +
780          ' Vui lòng đợi 1 vài phút rồi tải lại trang, nếu đơn hàng chưa được tạo thì mới mua đơn mới!');
781    },
782    complete: function() {
783      $("#submit").removeAttr("disabled");
784      $("#submit").removeClass("kt-spinner");
785      $("#submit").removeClass("kt-spinner--left");
786      $("#submit").removeClass("kt-spinner--md");
787      $("#submit").removeClass("kt-spinner--light");
788    }
789  });
790});
791
792function changePurchaseMultiOrderStatus(showStartBtn = true) {
793  $('.multi_order_btn_start')[showStartBtn ? 'show' : 'hide']();
794  $('#multi_order_btn_stop')[!showStartBtn ? 'show' : 'hide']();
795}
796
797function renderText(text) {
798  return ejs.render('<%= text %>', {text})
799}
800
801async function preparePurchaseMultiOrder() {
802  changePurchaseMultiOrderStatus(true);
803
804  multiOrderData.purchaseData = [];
805
806  const uidElement = $(multiOrderData.uidElementSelector);
807  if (!uidElement.length) return;
808  uidElement.val('');
809
810  const listUid = getContentArray($('#list_uid').val());
811
812  $('#modalMultiOrder').modal('show');
813  $('#multi_order_current_uid').text('N/A');
814  $('#multi_order_progress').text('N/A');
815
816  let index = 1;
817  for await (let string of listUid) {
818    swalLoading(`Đang get link ${index}/${listUid.length}`);
819
820    let purchaseInfo = await mo_getPurchaseInfo(string);
821    multiOrderData.purchaseData.push(purchaseInfo);
822    index++;
823
824    mo_showPurchaseInfo();
825  }
826
827  swalSuccess('Get UID hoàn tất, vui lòng kiểm tra lại các đơn hàng sẽ tạo trước khi tạo đơn!');
828}
829
830async function mo_getPurchaseInfo(string) {
831  let defaultQuantity = Number($(multiOrderData.countSelector).val()) || 1;
832  const singlePrice = multiOrderData.orderSubTotal / defaultQuantity;
833
834  let purchaseInfo = {
835    originId: string,
836    purchaseId: '',
837    purchaseName: '',
838    errorMsg: '',
839    uidError: false,
840    success: false,
841    quantity: defaultQuantity || 1,
842    orderTotal: multiOrderData.orderSubTotal
843  }
844
845  if ($(multiOrderData.customQuantitySelector).is(':checked')) {
846    let array = string.split('|').map(item => item.trim());
847    purchaseInfo.originId = array[0];
848    if (array[1]) purchaseInfo.quantity = Number(array[1]);
849    if (isNaN(purchaseInfo.quantity)) purchaseInfo.quantity = defaultQuantity;
850    if (!$(multiOrderData.countSelector).length) purchaseInfo.quantity = 1;
851
852    purchaseInfo.orderTotal = Math.floor(purchaseInfo.quantity * singlePrice);
853
854    string = array[0];
855  }
856  else if (string.includes('|')) {
857    string = string.split('|')[0];
858    purchaseInfo.originId =  string;
859  }
860
861  if (multiOrderData.idMap[string]) {
862    // Using data from cache
863    purchaseInfo.purchaseId = multiOrderData.idMap[string].purchaseId;
864    purchaseInfo.purchaseName = multiOrderData.idMap[string].purchaseName;
865  }
866  else {
867    let success, data;
868    switch (multiOrderData.elementType) {
869      case 'uid':
870        [success, data] = await getPostUid(string);
871        if (!success) {
872          purchaseInfo.errorMsg = data;
873        } else {
874          purchaseInfo.purchaseId = data;
875        }
876        break;
877
878      case 'link':
879        [success, data] = await getProfileInfo(string);
880        if (!success) {
881          purchaseInfo.errorMsg = data;
882        } else {
883          purchaseInfo.purchaseId = data.id;
884          purchaseInfo.purchaseName = data.name;
885        }
886        break;
887
888      case 'comment_link':
889        [success, data] = await getCommentLink(string);
890        if (!success) {
891          purchaseInfo.errorMsg = data;
892        } else {
893          purchaseInfo.purchaseId = data;
894        }
895        break;
896
897      case 'url':
898        [success, data] = await reFormatUrl(string);
899        if (!success) {
900          purchaseInfo.errorMsg = data;
901        } else {
902          purchaseInfo.purchaseId = data;
903        }
904        break;
905
906      case 'tiktok_post_link':
907        [success, data] = await getTiktokLink(string);
908        if (!success) {
909          purchaseInfo.errorMsg = data;
910        } else {
911          purchaseInfo.purchaseId = data;
912        }
913        break;
914
915      default:
916        purchaseInfo.purchaseId = string;
917        break;
918    }
919
920    if (purchaseInfo.purchaseId) multiOrderData.idMap[string] = purchaseInfo;
921    else purchaseInfo.uidError = true;
922  }
923
924  return purchaseInfo;
925}
926
927function mo_showPurchaseInfo() {
928  $('#modalMultiOrder tbody').html('');
929
930  multiOrderData.purchaseData.forEach((purchaseInfo, index) => {
931    // Append data to table
932    let htmlStatus = '';
933    if (purchaseInfo.errorMsg) htmlStatus = `<span class="text-danger">Lỗi: ${ renderText(purchaseInfo.errorMsg) }</span>`;
934    if (purchaseInfo.success) htmlStatus = `<span class="text-success">OK</span>`;
935
936    let extraText = '';
937    if (purchaseInfo.purchaseName) extraText = ` (${purchaseInfo.purchaseName})`;
938    let td2 = `<td class="text-success text-break-line">${ renderText(purchaseInfo.purchaseId + extraText) }</td>`;
939
940    if (purchaseInfo.uidError) {
941      td2 = `<td class="text-success"><button class="btn btn-success multi_order_btn_get_uid" data-index="${index}">Get UID</button></td>`
942    }
943
944    $('#modalMultiOrder tbody').append(
945        `
946            <tr>
947              <td class="text-primary text-break-line">${ renderText(purchaseInfo.originId) }</td>
948              ${td2}
949              <td>${purchaseInfo.quantity}</td>
950              <td class="text-warning">${ formatMoney(purchaseInfo.orderTotal) }VND</td>
951              <td>${ htmlStatus }</td>
952            </tr>
953        `
954    );
955  })
956}
957
958$('input').on('paste', function () {
959  var that = this;
960  setTimeout(function () {
961    $(that).blur();
962  }, 10);
963});
964
965function applyDiscountAndCurrency(total) {
966  $('#discount-status').attr('class', '');
967
968  total = vndToCurrentCurrency(total);
969
970  if (!sDiscount) return total;
971  const minOrder = vndToCurrentCurrency(sDiscount.min_order);
972
973  if (total < minOrder) {
974    $('#discount-status').addClass('text-danger').html(`Vui lòng tạo đơn tối thiểu 
975        <span>${formatMoney(minOrder, 'd')}</span> để sử dụng mã giảm giá này!`);
976    return total;
977  }
978
979  var willDiscount = round(total * (sDiscount.discount_percent / 100), 5);
980  if (currency == 'vnd') willDiscount = Math.floor(willDiscount);
981
982  const maxDiscount = vndToCurrentCurrency(sDiscount.max_discount);
983  if (willDiscount > maxDiscount) willDiscount = maxDiscount;
984
985  $('#discount-status').addClass('text-success').html(`Mã giảm giá đã được áp dụng! `+
986    `Bạn được giảm <span>${formatMoney(willDiscount, 'd', currency === 'vnd')}</span>`);
987
988  console.log(`Apply discount: ${total} - ${willDiscount} = ${total - willDiscount}`);
989  return total - willDiscount;
990}
991
992$("#count").change(function() {
993  if (typeof selfCalculatorPrice === "function") return selfCalculatorPrice();
994
995  var count = Number($(this).val());
996  var singlePrice = Number($("#price").attr('data-price'));
997  var total;
998
999  if (!(count > 0)) return toastr.error("Số lượng không được bé hơn 0");
1000  if (type.includes('livestream')) {
1001    var minuteElement = $('#minutes');
1002    var minutes = parseInt(minuteElement.val());
1003
1004    var minMinute = parseInt(minuteElement.attr('min'));
1005    var maxMinute = parseInt(minuteElement.attr('max'));
1006
1007    // Case has minutes
1008    if (minutes < minMinute || minutes > maxMinute) {
1009      toastr.error("Số phút xem video chưa hợp lệ (" +minMinute+ " - " +maxMinute+ ")");
1010      return;
1011    } else {
1012      total = count * singlePrice * minutes;
1013    }
1014  }
1015  else {
1016    total = count * singlePrice;
1017  }
1018
1019  if (type === 'view_telegram' && selectedServer === 'server_3') {
1020    total *= Number($('#formUserAction [name="post_count"]').val());
1021  }
1022
1023  $('#interval_order_total').text('');
1024  if (typeof selectedPrice == "object" && selectedPrice.allow_interval_order && $('#switch_interval_order').is(':checked')) {
1025    const orderCount = $('#section_interval_order [name=total_order]').val();
1026    if (orderCount && orderCount > 0) {
1027      total *= orderCount;
1028      $('#interval_order_total').text('(Tổng số lượng nhận được: ' + formatMoney(orderCount * count) + ')');
1029    }
1030  }
1031
1032  total = applyDiscountAndCurrency(total);
1033  total = getOrderTotal(total);
1034
1035  $("#total").val(formatMoney(total, ' VND'));
1036  toastr.success("Cập nhật giá thành công");
1037});
1038
1039function getOrderTotal(total) {
1040  multiOrderData.orderSubTotal = Number(total);
1041
1042  if ($('#switch_multi_order').is(':checked')) {
1043    const totalOrder = countLine($('#list_uid').val());
1044    total *= totalOrder;
1045
1046    if (totalOrder != 0) $('#total_order').text(totalOrder);
1047
1048    $("#total")
1049        .closest('.form-group')
1050        .find('label')
1051        .html(`Tổng Giá (<span class="text-success">${formatMoney(totalOrder)} đơn</span>)`)
1052  }
1053
1054  return total;
1055}
1056
1057// Handle for services in view
1058$('#services').change(function() {
1059  // Update price
1060  let selectedPrice = $(this).children("option:selected").data('price');
1061  $('#price').val(selectedPrice);
1062  // Trigger change
1063  $('#count').trigger('change');
1064});
1065
1066$("#cookie").change(function() {
1067  var cookie = $("#cookie").val();
1068  if (cookie) {
1069    toastr.info("Đang lấy thông tin từ cookie...");
1070    $.ajax({
1071      type: "POST",
1072      url: "/api/get-cookie",
1073      data: {cookie: cookie},
1074      success: function(response) {
1075        if(response.status === 1) {
1076          $("#name").val(response.data.name);
1077          $("#uid").val(response.data.uid);
1078          toastr.success("Get thông tin cookie thành công");
1079        } else {
1080          toastr.error(response.msg);
1081        }
1082      }
1083    });
1084  }
1085});
1086
1087$(document).on("click", ".btn-refund",function() {
1088  var id = $(this).attr("data-id");
1089  var tType = $(this).attr("data-type");
1090  swal.fire({
1091    title: 'Xóa?',
1092    text: `Bạn có muốn xóa ${tType} này!`,
1093    icon: 'warning',
1094    showCancelButton: true,
1095    confirmButtonText: 'Có',
1096    cancelButtonText: 'Không'
1097  }).then(result => {
1098    if (result.value) {
1099      $.ajax({
1100        type: "POST",
1101        url: `/vipfacebook/${tType}/refund`,
1102        data: `id=${id}&type=${tType}`,
1103        success: function(response) {
1104          if(response.status === 1) {
1105            swalSuccess(`Bạn đã xóa ${tType}.`);
1106            reloadTable();
1107          } else {
1108            swalError(`Lỗi: ${response.msg}`);
1109          }
1110        }
1111      });
1112    }
1113  });
1114});
1115
1116$(document).on("click", ".btn-re-check", async function() {
1117  var tType = $(this).data('type');
1118  var server = $(this).data('server');
1119  if (tType === 'follow' && server == 'server_1') {
1120    if (!await swalConfirm('Hãy kiểm tra lại nút theo dõi và bấm tiếp tục?')) return;
1121  }
1122
1123  swalLoading('Đang thực thi...');
1124  var id = $(this).attr("data-id");
1125  $.ajax({
1126    type: "POST",
1127    url: `/facebook/check_id`,
1128    data: {id: id},
1129    success: function(response) {
1130      if(response.status === 1) {
1131        swalSuccess('Thao thác thành công, chúng tôi sẽ kiểm tra lại trong thời gian sớm nhất');
1132        reloadTable();
1133      } else {
1134        swalError(response.msg);
1135      }
1136    }
1137  });
1138});
1139
1140$(document).on("click", ".btn-refund-buff", function() {
1141  var id = $(this).attr("data-id");
1142  swalConfirm('Huỷ đơn sẽ hoàn tiền số lượng chưa chạy và trừ 2k phí?').then(function(confirm) {
1143    if (!confirm) return;
1144
1145    swalLoading('Đang thực thi...');
1146    $.ajax({
1147      type: "POST",
1148      url: `/facebook/refund`,
1149      data: {id: id},
1150      success: function(response) {
1151        if (response.status === 1) {
1152          swalSuccess('Thao thác thành công!');
1153          if (datatableLog) datatableLog.ajax.reload(null, false);
1154        } else {
1155          swalError(response.msg);
1156        }
1157      }
1158    });
1159  });
1160});
1161
1162$(document).on("click", ".btn-delete-buff",function() {
1163  swalLoading('Đang thực thi...');
1164  var id = $(this).attr("data-id");
1165  $.ajax({
1166    type: "POST",
1167    url: `/facebook/delete-m`,
1168    data: {id: id},
1169    success: function(response) {
1170      if(response.status === 1) {
1171        swalSuccess('Thao thác thành công!');
1172        if (datatableLog) datatableLog.ajax.reload(null, false);
1173      } else {
1174        swalError(response.msg);
1175      }
1176    }
1177  });
1178});
1179
1180$(document).on("click", ".btn-delete-expired", function () {
1181  var id = $(this).attr("data-id");
1182  swalConfirm().then(confirm => {
1183    if (!confirm) return;
1184
1185    swalLoading();
1186    callAjaxPost('/vip/delete_expired', {id: id}).then(function(response) {
1187      if (response.status == 1) {
1188        $('.modal.show').modal('hide');
1189        reloadTable();
1190        swalSuccess(response.msg);
1191      } else {
1192        swalError(response.msg);
1193      }
1194    });
1195  });
1196});
1197
1198$('#price').keyup(function () {
1199  $('#count').trigger('change');
1200});
1201
1202$('#price').change(function () {
1203  $('#count').trigger('change');
1204});
1205
1206$('.btn-view-history').click(function() {
1207  var target = $(this).data('target');
1208  $('a.nav-link[href="' +target+ '"]').trigger('click');
1209  $([document.documentElement, document.body]).animate({
1210    scrollTop: $(target).offset().top - 100
1211  }, 500);
1212});
1213
1214$('.has_count').keyup(function() {
1215  $($(this).data('counter')).html(countLine($(this).val()));
1216});
1217
1218$(document).on("click", ".btn-extend-vip", async function () {
1219  var id = $(this).data('id');
1220
1221  var days = await swalInput('Nhập số ngày bạn muốn gia hạn', 30);
1222  if (!days) return;
1223
1224  swalLoading('Đang thực thi, vui lòng không tắt hộp thoại này!');
1225  $.post(`/vip/extend/`, {id: id, days: days}).done(handleVipAction)
1226});
1227
1228$('[name="list_comment"], [name="comment"], [name=comments]').change(function() {
1229  $(this).val(getContentArray($(this).val()).join("\n"));
1230});
1231
1232
1233const USD_RATE = 24_000;
1234const BATH_RATE = 739;
1235
1236const vndToCurrentCurrency = (value, formatText = false, target = null) => {
1237  if (typeof value !== 'number') value = Number(value.toString().replace(/,/g, ''));
1238
1239  if (currency == 'vnd' && !target) {
1240    if (!formatText) return value;
1241    return formatMoney(value, '', false);
1242  }
1243
1244  let rate = USD_RATE;
1245  let places = 5;
1246
1247  if ((currency == 'baht' && !target) || target == 'baht') {
1248    rate = BATH_RATE;
1249    places = 4;
1250  }
1251
1252  value = round(value / rate, places);
1253  if (!formatText) return value;
1254  return formatMoney(value, '', false);
1255}
1256
1257const currencyMap = {
1258  vnd: formatMoney(userBalance),
1259  usd: vndToCurrentCurrency(userBalance, true,  'usd'),
1260  baht: vndToCurrentCurrency(userBalance, true, 'baht'),
1261}
1262const currencyCharsMap = {
1263  vnd: '₫',
1264  usd: '$',
1265  baht: '฿'
1266}
1267
1268$('.currency-select').each(function() {
1269  const that = this;
1270  Object.keys(currencyMap).forEach(item => {
1271    $(that).append(`<option value="${item}">${currencyMap[item]} ${currencyCharsMap[item]}</option>`);
1272  })
1273})
1274    .val(currency)
1275    .change(function() {
1276      currency = $(this).val();
1277      changeCurrency();
1278
1279      callAjaxPost( '/setting', {currency}).then(() => {
1280        if (typeof type !== 'undefined' && ['vip_live'].includes(type)) {
1281          return window.location.reload();
1282        }
1283      });
1284
1285      $('.currency-dropdown .dropdown-toggle').dropdown('toggle');
1286
1287      const activeServer = $('.radio.radio-server:not(.pause,.stopped) input[name="server"]');
1288      if (activeServer.length) {
1289        activeServer.first().trigger('change');
1290      } else {
1291        $('#count').trigger('change');
1292      }
1293    });
1294
1295// Change currency (text only)
1296function changeCurrency() {
1297  $('.money-value').each(function() {
1298    if (!$(this).attr('data-original')) $(this).attr('data-original', $(this).text());
1299    // ignore if translated
1300    if ($(this).attr('data-currency') == currency) return;
1301    // if vnd
1302    if (currency === 'vnd' && !$(this).attr('data-currency')) return;
1303
1304    const vndValue = $(this).attr('data-original').toString().replace(/,/g, '');
1305
1306    $(this).text(vndToCurrentCurrency(Number(vndValue), true));
1307
1308    $(this).attr('data-currency', currency);
1309  });
1310  $('.currency-unit').text(currencyCharsMap[currency]);
1311}
1312
1313if (currency !== 'vnd') changeCurrency();
1314
1315$('.currency-dropdown .dropdown-menu *').click(function(e) {
1316  e.stopPropagation();
1317});
1318
1319

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.