PluginProbe
ووسلام – همگام سازی ووکامرس و باسلام / 1.10.22
ووسلام – همگام سازی ووکامرس و باسلام v1.10.22
1.10.22 1.10.21 1.10.19 1.10.20 1.10.18 1.10.17 1.10.15 1.10.14 1.10.13 1.10.12 1.10.10 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.2 1.9.1 1.9.0 1.8.8 All 55 releases
sync-basalam / assets / js / admin.js

admin.js in ووسلام – همگام سازی ووکامرس و باسلام 1.10.22, at assets/js/admin.js

1,210 lines 35.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 document.addEventListener("DOMContentLoaded", function () {
2 const modalConfig = [
3 {
4 key: "add",
5 modalId: "basalamAddProductsModal",
6 openBtnId: "basalamOpenAddProductsModal",
7 formId: "basalamAddProductsForm",
8 action: "create_products_to_basalam",
9 },
10 {
11 key: "update",
12 modalId: "BasalamUpdateProductsModal",
13 openBtnId: "BasalamOpenUpdateProductsModal",
14 formId: "BasalamUpdateProductsForm",
15 action: "update_products_in_basalam",
16 },
17 {
18 key: "connect",
19 modalId: "BasalamConnectProductsModal",
20 openBtnId: "BasalamOpenConnectProductsModal",
21 formId: "BasalamConnectProductsForm",
22 action: "connect_products_with_basalam",
23 },
24 ];
25
26 const updateModal = document.getElementById("BasalamUpdateProductsModal");
27 let updateStatusPoller = null;
28 let updateStatusInFlight = false;
29
30 const showUpdatePanel = (panelId) => {
31 ["update-status-loading", "update-status-error", "update-type-selection", "quick-update-in-progress", "active-jobs-info"].forEach((id) => {
32 const panel = document.getElementById(id);
33 if (panel) panel.hidden = id !== panelId;
34 });
35 };
36
37 const refreshUpdateStatus = () => {
38 if (!updateModal || !document.getElementById("update-type-selection") || updateStatusInFlight) return;
39
40 updateStatusInFlight = true;
41 const formData = new FormData();
42 formData.append("action", "get_update_queue_status");
43 formData.append("_wpnonce", updateModal.dataset.statusNonce || "");
44
45 return fetch(ajaxurl, { method: "POST", body: formData, cache: "no-store" })
46 .then((response) => response.json())
47 .then((response) => {
48 if (!response.success || !response.data) throw new Error("Update status unavailable");
49
50 const status = response.data;
51 if (!status.active) {
52 showUpdatePanel("update-type-selection");
53 } else if (status.type === "quick") {
54 const badge = document.getElementById("quick-update-status");
55 if (badge) badge.textContent = status.status === "processing" ? "در حال پردازش" : "در انتظار";
56 showUpdatePanel("quick-update-in-progress");
57 } else {
58 const count = Number(status.count) || 0;
59 const countRow = document.getElementById("update-queue-count-row");
60 const countBadge = document.getElementById("update-queue-count");
61 if (countRow) countRow.hidden = count === 0;
62 if (countBadge) countBadge.textContent = `${count} �
63 حصول`;
64 showUpdatePanel("active-jobs-info");
65 }
66 })
67 .catch((error) => {
68 console.error("Error fetching product update status:", error);
69 showUpdatePanel("update-status-error");
70 })
71 .finally(() => {
72 updateStatusInFlight = false;
73 });
74 };
75
76 const closeModal = () => {
77 if (updateStatusPoller) {
78 clearInterval(updateStatusPoller);
79 updateStatusPoller = null;
80 }
81 document.querySelectorAll(".basalam-modal").forEach((modal) => {
82 modal.style.display = "none";
83 });
84 document.body.style.overflow = "auto";
85 };
86
87 modalConfig.forEach(({ modalId, openBtnId, formId, action }) => {
88 const modal = document.getElementById(modalId);
89 const openBtn = document.getElementById(openBtnId);
90 const form = document.getElementById(formId);
91
92 if (openBtn && modal) {
93 openBtn.addEventListener("click", () => {
94 modal.style.display = "block";
95 document.body.style.overflow = "hidden";
96
97 if (modalId === "BasalamUpdateProductsModal") {
98 if (document.getElementById("update-type-selection")) {
99 showUpdatePanel("update-status-loading");
100 refreshUpdateStatus();
101 if (updateStatusPoller) clearInterval(updateStatusPoller);
102 updateStatusPoller = setInterval(refreshUpdateStatus, 5000);
103 }
104 }
105 });
106 }
107
108 if (form) {
109 form.addEventListener("submit", function (e) {
110 e.preventDefault();
111
112 if (action === "create_products_to_basalam") {
113 const confirmModal = document.getElementById("BasalamConfirmModal");
114 confirmModal.style.display = "block";
115 document.body.style.overflow = "hidden";
116
117 const confirmButton = document.getElementById("confirmSubmitBtn");
118
119 const newConfirmBtn = confirmButton.cloneNode(true);
120 confirmButton.parentNode.replaceChild(newConfirmBtn, confirmButton);
121
122 newConfirmBtn.addEventListener("click", function () {
123 confirmModal.style.display = "none";
124
125 submitToServer(form, action);
126 });
127 } else {
128 submitToServer(form, action);
129 }
130 });
131 }
132 });
133
134 document.getElementById("update-status-retry")?.addEventListener("click", () => {
135 showUpdatePanel("update-status-loading");
136 refreshUpdateStatus();
137 });
138
139 setTimeout(() => {
140 const quickUpdateBtn = document.getElementById("quick-update-btn");
141 const fullUpdateBtn = document.getElementById("full-update-btn");
142
143 if (quickUpdateBtn) {
144 quickUpdateBtn.addEventListener("click", (e) => {
145 e.preventDefault();
146
147 const formData = new FormData();
148 formData.append("update_type", "quick");
149 formData.append("action", "update_products_in_basalam");
150 formData.append(
151 "_wpnonce",
152 document.querySelector(
153 '#BasalamUpdateProductsModal input[name="_wpnonce"]'
154 )?.value || ""
155 );
156
157 submitUpdateRequest(formData, "quick");
158 });
159 }
160
161 if (fullUpdateBtn) {
162 fullUpdateBtn.addEventListener("click", (e) => {
163 e.preventDefault();
164
165 const formData = new FormData();
166 formData.append("update_type", "full");
167 formData.append("action", "update_products_in_basalam");
168 formData.append(
169 "_wpnonce",
170 document.querySelector(
171 '#BasalamUpdateProductsModal input[name="_wpnonce"]'
172 )?.value || ""
173 );
174
175 submitUpdateRequest(formData, "full");
176 });
177 }
178 }, 100);
179
180 function submitUpdateRequest(formData, updateType) {
181 const quickBtn = document.getElementById("quick-update-btn");
182 const fullBtn = document.getElementById("full-update-btn");
183
184 if (quickBtn) quickBtn.disabled = true;
185 if (fullBtn) fullBtn.disabled = true;
186
187 const clickedBtn = updateType === "quick" ? quickBtn : fullBtn;
188 if (clickedBtn) {
189 const originalText = clickedBtn.innerHTML;
190 clickedBtn.innerHTML =
191 '<span class="basalam-loading-text">در حال ارسال...</span>';
192
193 fetch(ajaxurl, {
194 method: "POST",
195 body: formData,
196 })
197 .then((response) => response.json())
198 .then((data) => {
199 closeModal();
200 if (data.success) {
201 window.BasalamToast.success(data.data?.message || "ع�
202 لیات با �
203 وفقیت آغاز شد.");
204 } else {
205 window.BasalamToast.error(data.data?.message || "خطایی رخ داده است.");
206 }
207 location.reload();
208 })
209 .catch((error) => {
210 console.error("Error:", error);
211 window.BasalamToast.error("خطایی در ارسال رخ داده است.");
212
213 if (quickBtn) quickBtn.disabled = false;
214 if (fullBtn) fullBtn.disabled = false;
215 if (clickedBtn) clickedBtn.innerHTML = originalText;
216 });
217 }
218 }
219
220 function submitToServer(form, action, updateType = null) {
221 const formData = new FormData(form);
222 formData.append("action", action);
223
224 const submitButton = form.querySelector('button[type="submit"]');
225 submitButton.disabled = true;
226 submitButton.innerHTML =
227 '<span class="dashicons dashicons-update"></span> در حال ارسال...';
228
229 fetch(ajaxurl, {
230 method: "POST",
231 body: formData,
232 })
233 .then((response) => response.json())
234 .then((data) => {
235 closeModal();
236 if (data.success) {
237 window.BasalamToast.success(data.data?.message || "ع�
238 لیات با �
239 وفقیت آغاز شد.");
240 } else {
241 window.BasalamToast.error(data.data?.message || "خطایی رخ داده است.");
242 }
243 location.reload();
244 })
245 .catch((error) => {
246 console.error("Error:", error);
247 window.BasalamToast.error("خطایی در ارسال رخ داده است.");
248 })
249 .finally(() => {
250 submitButton.disabled = false;
251 submitButton.innerHTML =
252 '<span class="dashicons dashicons-plus-alt"></span> انجا�
253 شد';
254 });
255 }
256
257 document.querySelectorAll(".basalam-modal-close").forEach((btn) => {
258 btn.addEventListener("click", closeModal);
259 });
260
261 window.addEventListener("click", (event) => {
262 if (event.target.classList.contains("basalam-modal")) {
263 closeModal();
264 }
265 });
266
267 document.addEventListener("keydown", (event) => {
268 if (event.key === "Escape") {
269 closeModal();
270 }
271 });
272
273 const select = document.getElementById("basalam-sync-type");
274 if (select) {
275 const customFields = document.getElementById("Basalam-custom-fields");
276 const settingsForm = select.closest("form");
277 const validationMessage =
278 "در حالت سفارشی باید حداقل یک فیلد را برای بروزرسانی انتخاب کنید.";
279
280 const toggleFields = (val) => {
281 if (customFields) {
282 customFields.style.display = val === "custom" ? "block" : "none";
283 }
284 };
285
286 const hasSelectedCustomField = () =>
287 customFields &&
288 Array.from(
289 customFields.querySelectorAll('input[type="checkbox"]')
290 ).some((checkbox) => checkbox.checked);
291
292 toggleFields(select.value);
293 select.addEventListener("change", (e) => toggleFields(e.target.value));
294
295 if (settingsForm) {
296 settingsForm.addEventListener("submit", (event) => {
297 if (select.value !== "custom" || hasSelectedCustomField()) return;
298
299 event.preventDefault();
300 event.stopImmediatePropagation();
301
302 if (window.BasalamToast) {
303 window.BasalamToast.error(validationMessage);
304 }
305
306 if (customFields) {
307 customFields.scrollIntoView({ behavior: "smooth", block: "center" });
308 customFields.querySelector('input[type="checkbox"]')?.focus();
309 }
310 }, true);
311 }
312 }
313
314 // Tab functionality for settings modal
315 const initTabs = () => {
316 const tabBtns = document.querySelectorAll(".basalam-tab-btn");
317 const tabContents = document.querySelectorAll(".basalam-tab-content");
318
319 tabBtns.forEach((btn) => {
320 btn.addEventListener("click", () => {
321 const tabId = btn.getAttribute("data-tab");
322
323 // Remove active class from all buttons and contents
324 tabBtns.forEach((b) => b.classList.remove("active"));
325 tabContents.forEach((c) => c.classList.remove("active"));
326
327 // Add active class to clicked button and corresponding content
328 btn.classList.add("active");
329 const content = document.getElementById(tabId);
330 if (content) {
331 content.classList.add("active");
332 }
333 });
334 });
335 };
336
337 initTabs();
338
339 const initPointerOnboarding = () => {
340 const pointerTour = window.basalamPointerTour;
341
342 if (
343 !pointerTour ||
344 !Array.isArray(pointerTour.steps) ||
345 pointerTour.steps.length === 0
346 ) {
347 return;
348 }
349
350 if (
351 typeof window.jQuery === "undefined" ||
352 typeof window.jQuery.fn.pointer !== "function"
353 ) {
354 return;
355 }
356
357 const steps = pointerTour.steps.filter(
358 (step) =>
359 step &&
360 typeof step.selector === "string" &&
361 document.querySelector(step.selector)
362 );
363
364 if (steps.length === 0) {
365 return;
366 }
367
368 let completionRequested = false;
369
370 const markTourCompleted = () => {
371 if (completionRequested) {
372 return;
373 }
374
375 completionRequested = true;
376
377 if (!pointerTour.completeAction || !pointerTour.nonce) {
378 return;
379 }
380
381 const formData = new FormData();
382 formData.append("action", pointerTour.completeAction);
383 formData.append("nonce", pointerTour.nonce);
384
385 fetch(ajaxurl, {
386 method: "POST",
387 body: formData,
388 }).catch(() => {});
389 };
390
391 const openStep = (index) => {
392 if (index >= steps.length) {
393 markTourCompleted();
394 return;
395 }
396
397 const step = steps[index];
398 const $target = window.jQuery(step.selector).first();
399
400 if (!$target.length) {
401 openStep(index + 1);
402 return;
403 }
404
405 const targetElement = $target.get(0);
406 if (targetElement && typeof targetElement.scrollIntoView === "function") {
407 targetElement.scrollIntoView({ behavior: "smooth", block: "center" });
408 }
409
410 let shouldAdvance = false;
411 let shouldStop = false;
412
413 $target
414 .pointer({
415 pointerClass: "sync-basalam-pointer",
416 content: step.content || "",
417 position: step.position || { edge: "right", align: "middle" },
418 buttons: function (event, t) {
419 const isLastStep = index === steps.length - 1;
420 const skipLabel = step.skipLabel || "بستن";
421 const nextLabel = isLastStep
422 ? step.doneLabel || "ات�
423 ا�
424 "
425 : step.nextLabel || "بعدی";
426
427 const $skipButton = window.jQuery(
428 '<button type="button" class="button button-secondary"></button>'
429 ).text(skipLabel);
430
431 const $nextButton = window.jQuery(
432 '<button type="button" class="button button-primary"></button>'
433 ).text(nextLabel);
434
435 $skipButton.on("click", function () {
436 shouldStop = true;
437 t.element.pointer("close");
438 });
439
440 $nextButton.on("click", function () {
441 shouldAdvance = true;
442 t.element.pointer("close");
443 });
444
445 return window.jQuery('<div class="wp-pointer-buttons" />')
446 .append($skipButton)
447 .append($nextButton);
448 },
449 close: function () {
450 if (shouldStop) {
451 markTourCompleted();
452 return;
453 }
454
455 if (shouldAdvance) {
456 openStep(index + 1);
457 return;
458 }
459
460 markTourCompleted();
461 },
462 })
463 .pointer("open");
464 };
465
466 openStep(0);
467 };
468
469 initPointerOnboarding();
470
471 const initAnnouncementsPanel = () => {
472 const announcementsConfig = window.basalamAnnouncements;
473
474 if (
475 !announcementsConfig ||
476 !Array.isArray(announcementsConfig.items) ||
477 announcementsConfig.items.length === 0
478 ) {
479 return;
480 }
481
482 const root = document.getElementById("sync-basalam-announcement-root");
483 const trigger = document.getElementById("sync-basalam-announcement-trigger");
484 const panel = document.getElementById("sync-basalam-announcement-panel");
485 const overlay = document.getElementById("sync-basalam-announcement-overlay");
486 const closeBtn = document.getElementById("sync-basalam-announcement-close");
487 const counter = document.getElementById("sync-basalam-announcement-counter");
488 const list = document.getElementById("sync-basalam-announcement-list");
489 const pageIndicator = document.getElementById("sync-basalam-announcement-page");
490 const prevBtn = document.getElementById("sync-basalam-announcement-prev");
491 const nextBtn = document.getElementById("sync-basalam-announcement-next");
492
493 if (
494 !root ||
495 !trigger ||
496 !panel ||
497 !overlay ||
498 !closeBtn ||
499 !counter ||
500 !list ||
501 !pageIndicator ||
502 !prevBtn ||
503 !nextBtn
504 ) {
505 return;
506 }
507
508 const normalizeItems = (rawItems) =>
509 rawItems
510 .map((item) => {
511 const files = Array.isArray(item?.files) ? item.files : [];
512 const imageFile = files.find((f) => f?.url && /\.(png|jpe?g|gif|webp|svg)/i.test(f.url));
513
514 return {
515 id: String(item?.id || ""),
516 description: String(item?.description || ""),
517 link: String(item?.link || "#"),
518 linkText: String(item?.linkText || "ادا�
519 ه"),
520 image: imageFile ? String(imageFile.url) : (item?.image ? String(item.image) : ""),
521 };
522 })
523 .filter((item) => item.id && item.description);
524
525 let items = normalizeItems(announcementsConfig.items);
526
527 if (items.length === 0) {
528 root.remove();
529 return;
530 }
531
532 let currentPage = 1;
533 let totalPages = Math.max(parseInt(announcementsConfig.totalPage, 10) || 1, 1);
534 let isFetching = false;
535
536 let seenIds = new Set(
537 Array.isArray(announcementsConfig.seenIds)
538 ? announcementsConfig.seenIds.map((id) => String(id))
539 : []
540 );
541 let seenRequested = false;
542
543 const getUnreadCount = () =>
544 items.reduce((total, item) => total + (seenIds.has(item.id) ? 0 : 1), 0);
545
546 const updateCounter = () => {
547 const unreadCount = getUnreadCount();
548 counter.textContent = String(unreadCount);
549 counter.classList.toggle(
550 "sync-basalam-announcement-counter-hidden",
551 unreadCount === 0
552 );
553 };
554
555 const renderItems = (pageItems) => {
556 list.innerHTML = "";
557
558 pageItems.forEach((item) => {
559 const card = document.createElement("article");
560 card.className =
561 "sync-basalam-announcement-card" +
562 (item.image ? "" : " sync-basalam-announcement-card-no-image") +
563 (seenIds.has(item.id) ? " is-seen" : " is-unread");
564
565 if (item.image) {
566 const imageWrapper = document.createElement("div");
567 imageWrapper.className = "sync-basalam-announcement-image-wrap";
568
569 const image = document.createElement("img");
570 image.className = "sync-basalam-announcement-image";
571 image.src = item.image;
572 image.alt = "خبر ووسلا�
573 ";
574 image.loading = "lazy";
575
576 imageWrapper.appendChild(image);
577 card.appendChild(imageWrapper);
578 }
579
580 const content = document.createElement("div");
581 content.className = "sync-basalam-announcement-content";
582
583 const description = document.createElement("p");
584 description.className = "sync-basalam-announcement-text";
585 description.textContent = item.description;
586
587 const link = document.createElement("a");
588 link.className = "sync-basalam-announcement-link";
589 link.href = item.link;
590 link.textContent = item.linkText || "ادا�
591 ه";
592 link.target = "_blank";
593 link.rel = "noopener noreferrer";
594
595 content.appendChild(description);
596 if (item.link && item.link !== "#") {
597 content.appendChild(link);
598 }
599 card.appendChild(content);
600 list.appendChild(card);
601 });
602 };
603
604 const updatePagination = () => {
605 pageIndicator.textContent = `${currentPage} / ${totalPages}`;
606 prevBtn.disabled = currentPage <= 1 || isFetching;
607 nextBtn.disabled = currentPage >= totalPages || isFetching;
608 };
609
610 const renderPage = () => {
611 renderItems(items);
612 updatePagination();
613 };
614
615 const fetchPage = (page) => {
616 if (isFetching) {
617 return;
618 }
619
620 isFetching = true;
621 prevBtn.disabled = true;
622 nextBtn.disabled = true;
623 list.innerHTML = '<div class="sync-basalam-announcement-loading">در حال بارگذاری...</div>';
624
625 const formData = new FormData();
626 formData.append("action", announcementsConfig.fetchPageAction || "");
627 formData.append("nonce", announcementsConfig.fetchPageNonce || "");
628 formData.append("page", String(page));
629
630 fetch(ajaxurl, {
631 method: "POST",
632 body: formData,
633 })
634 .then((response) => response.json())
635 .then((data) => {
636 if (!data?.success) {
637 return;
638 }
639
640 const newItems = normalizeItems(data.data.items || []);
641 items = newItems;
642 currentPage = parseInt(data.data.page, 10) || page;
643 totalPages = parseInt(data.data.totalPage, 10) || totalPages;
644
645 renderPage();
646 })
647 .catch(() => {
648 updatePagination();
649 })
650 .finally(() => {
651 isFetching = false;
652 updatePagination();
653 });
654 };
655
656 const markAllSeen = () => {
657 if (seenRequested || getUnreadCount() === 0) {
658 return;
659 }
660
661 seenRequested = true;
662
663 const formData = new FormData();
664 formData.append("action", announcementsConfig.markSeenAction || "");
665 formData.append("nonce", announcementsConfig.nonce || "");
666
667 fetch(ajaxurl, {
668 method: "POST",
669 body: formData,
670 })
671 .then((response) => response.json())
672 .then((data) => {
673 if (!data?.success) {
674 return;
675 }
676
677 seenIds = new Set(items.map((item) => item.id));
678 updateCounter();
679 renderPage();
680 })
681 .catch(() => {})
682 .finally(() => {
683 seenRequested = false;
684 });
685 };
686
687 const openPanel = () => {
688 root.classList.add("is-open");
689 panel.setAttribute("aria-hidden", "false");
690 document.body.classList.add("sync-basalam-announcement-open");
691 markAllSeen();
692 };
693
694 const closePanel = () => {
695 root.classList.remove("is-open");
696 panel.setAttribute("aria-hidden", "true");
697 document.body.classList.remove("sync-basalam-announcement-open");
698 };
699
700 trigger.addEventListener("click", openPanel);
701 closeBtn.addEventListener("click", closePanel);
702 overlay.addEventListener("click", closePanel);
703
704 document.addEventListener("mousedown", (event) => {
705 if (!root.classList.contains("is-open")) {
706 return;
707 }
708
709 const target = event.target;
710 if (!(target instanceof Node)) {
711 return;
712 }
713
714 if (panel.contains(target) || trigger.contains(target)) {
715 return;
716 }
717
718 closePanel();
719 });
720
721 prevBtn.addEventListener("click", () => {
722 if (currentPage <= 1 || isFetching) {
723 return;
724 }
725 fetchPage(currentPage - 1);
726 });
727
728 nextBtn.addEventListener("click", () => {
729 if (currentPage >= totalPages || isFetching) {
730 return;
731 }
732 fetchPage(currentPage + 1);
733 });
734
735 document.addEventListener("keydown", (event) => {
736 if (event.key === "Escape" && root.classList.contains("is-open")) {
737 closePanel();
738 }
739 });
740
741 updateCounter();
742 renderPage();
743 };
744
745 initAnnouncementsPanel();
746
747 const advancedSettingsForm = document.getElementById(
748 "basalam-advanced-settings-form"
749 );
750 const advancedSubmitSection = document.getElementById(
751 "basalam-advanced-submit-section"
752 );
753
754 const isTrackedAdvancedSettingField = (fieldName) =>
755 typeof fieldName === "string" &&
756 fieldName.startsWith("sync_basalam_settings[");
757
758 if (advancedSettingsForm && advancedSubmitSection) {
759 const serializeAdvancedSettings = () => {
760 const formData = new FormData(advancedSettingsForm);
761 const entries = [];
762
763 formData.forEach((value, key) => {
764 if (isTrackedAdvancedSettingField(key)) {
765 entries.push(`${key}=${String(value)}`);
766 }
767 });
768
769 return entries.join("&");
770 };
771
772 let initialSettingsSnapshot = "";
773
774 const toggleAdvancedSubmitVisibility = () => {
775 const currentSnapshot = serializeAdvancedSettings();
776 const hasChanges = currentSnapshot !== initialSettingsSnapshot;
777
778 advancedSubmitSection.classList.toggle(
779 "basalam-submit-section-hidden",
780 !hasChanges
781 );
782 };
783
784 const captureInitialSnapshot = () => {
785 initialSettingsSnapshot = serializeAdvancedSettings();
786 toggleAdvancedSubmitVisibility();
787 };
788
789 const handleSettingsFieldMutation = (event) => {
790 const fieldName = event.target?.name || "";
791
792 if (!isTrackedAdvancedSettingField(fieldName)) {
793 return;
794 }
795
796 window.requestAnimationFrame(toggleAdvancedSubmitVisibility);
797 };
798
799 advancedSettingsForm.addEventListener("input", handleSettingsFieldMutation);
800 advancedSettingsForm.addEventListener(
801 "change",
802 handleSettingsFieldMutation
803 );
804
805 captureInitialSnapshot();
806 window.requestAnimationFrame(captureInitialSnapshot);
807 }
808
809 const infoTriggers = document.querySelectorAll(".basalam-info-trigger");
810
811 const moveModalsToBody = () => {
812 const allModals = document.querySelectorAll(".basalam-info-modal");
813 allModals.forEach((modal) => {
814 if (modal.parentNode !== document.body) {
815 document.body.appendChild(modal);
816 }
817 });
818 };
819
820 moveModalsToBody();
821
822 const closeAllModals = () => {
823 const allModals = document.querySelectorAll(".basalam-info-modal");
824 allModals.forEach((modal) => {
825 modal.style.display = "none";
826 modal.classList.remove("show");
827 });
828 document.body.style.overflow = "auto";
829 };
830
831 const openModal = (modalId) => {
832 const modal = document.getElementById(modalId);
833 if (modal) {
834 if (modal.parentNode !== document.body) {
835 document.body.appendChild(modal);
836 }
837
838 modal.style.display = "block";
839 modal.classList.add("show");
840 document.body.style.overflow = "hidden";
841
842 modal.focus();
843 }
844 };
845
846 infoTriggers.forEach((trigger) => {
847 trigger.addEventListener("click", (e) => {
848 e.preventDefault();
849 e.stopPropagation();
850
851 const modalId = trigger.getAttribute("data-modal-id");
852 if (modalId) {
853 openModal(modalId);
854 }
855 });
856 });
857
858 document.addEventListener("click", (e) => {
859 if (e.target.classList.contains("basalam-info-modal-close")) {
860 e.preventDefault();
861 closeAllModals();
862 }
863
864 if (e.target.classList.contains("basalam-info-modal-overlay")) {
865 closeAllModals();
866 }
867
868 if (e.target.classList.contains("basalam-info-modal")) {
869 closeAllModals();
870 }
871 });
872
873 document.addEventListener("keydown", (e) => {
874 if (e.key === "Escape") {
875 closeAllModals();
876 }
877 });
878
879 document.addEventListener("click", (e) => {
880 if (e.target.closest(".basalam-info-modal-content")) {
881 e.stopPropagation();
882 }
883 });
884
885 const tasksAutoToggle = document.querySelector(".basalam-tasks-auto-toggle");
886 const tasksManualContainer = document.querySelector(
887 ".basalam-tasks-manual-container"
888 );
889 const tasksManualInput = document.querySelector(
890 ".basalam-tasks-manual-input"
891 );
892 const tasksAutoHidden = document.querySelector(".basalam-tasks-auto-hidden");
893
894 const toggleTasksManualInput = () => {
895 if (tasksAutoToggle && tasksManualInput) {
896 const isAuto = tasksAutoToggle.checked;
897
898 if (isAuto) {
899 tasksManualInput.disabled = true;
900 if (tasksAutoHidden) tasksAutoHidden.disabled = true;
901 } else {
902 tasksManualInput.disabled = false;
903 if (tasksAutoHidden) tasksAutoHidden.disabled = false;
904 }
905 }
906 };
907
908 if (tasksAutoToggle) {
909 tasksAutoToggle.addEventListener("change", toggleTasksManualInput);
910 }
911
912 // Attribute suffix toggle handler
913 const attributeSuffixToggle = document.querySelector(
914 ".basalam-attribute-suffix-toggle"
915 );
916 const attributeSuffixPriority = document.querySelector(
917 ".basalam-attribute-suffix-priority"
918 );
919 const attributeSuffixContainer = document.querySelector(
920 ".basalam-attribute-suffix-container"
921 );
922 const attributeSuffixHidden = document.querySelector(
923 ".basalam-attribute-suffix-hidden"
924 );
925
926 const toggleAttributeSuffixPriority = () => {
927 if (attributeSuffixToggle) {
928 const isEnabled = attributeSuffixToggle.checked;
929
930 if (attributeSuffixPriority) {
931 attributeSuffixPriority.disabled = !isEnabled;
932 }
933
934 if (attributeSuffixContainer) {
935 attributeSuffixContainer.style.display = isEnabled ? "block" : "none";
936 }
937
938 if (attributeSuffixHidden) {
939 attributeSuffixHidden.disabled = isEnabled;
940 }
941 }
942 };
943
944 if (attributeSuffixToggle) {
945 attributeSuffixToggle.addEventListener(
946 "change",
947 toggleAttributeSuffixPriority
948 );
949 // Initialize on page load
950 toggleAttributeSuffixPriority();
951 }
952
953 const initBulkEditFields = () => {
954 const SYNC_BASALAM_BULK_ACTION = "sync_basalam_bulk_edit";
955
956 const syncTypeVisibility = () => {
957 document
958 .querySelectorAll('select[name="sync_basalam_bulk_product_type_action"]')
959 .forEach((select) => {
960 const container = select
961 .closest(".sync-basalam-bulk-edit")
962 ?.querySelector(".sync-basalam-bulk-type-fields");
963
964 if (container) {
965 container.style.display = select.value === "yes" ? "flex" : "none";
966 }
967 });
968 };
969
970 const syncPriceChangeVisibility = () => {
971 document
972 .querySelectorAll('select[name="sync_basalam_bulk_price_change_action"]')
973 .forEach((select) => {
974 const field = select
975 .closest(".sync-basalam-bulk-edit")
976 ?.querySelector(".sync-basalam-bulk-price-change-value");
977
978 if (field) {
979 field.style.display = select.value === "set" ? "block" : "none";
980 }
981 });
982 };
983
984 const setBulkEditMode = (mode) => {
985 const bulkRow = document.getElementById("bulk-edit");
986 if (!bulkRow) {
987 return;
988 }
989
990 bulkRow.classList.remove("sync-basalam-bulk-mode", "sync-basalam-default-bulk-mode");
991 bulkRow.classList.add(mode === "basalam" ? "sync-basalam-bulk-mode" : "sync-basalam-default-bulk-mode");
992 };
993
994 const openBasalamBulkEditor = (sourceSelect) => {
995 if (!window.inlineEditPost || typeof window.inlineEditPost.setBulk !== "function") {
996 return;
997 }
998
999 setBulkEditMode("basalam");
1000
1001 sourceSelect.value = "edit";
1002 window.inlineEditPost.setBulk();
1003 sourceSelect.value = SYNC_BASALAM_BULK_ACTION;
1004
1005 window.requestAnimationFrame(() => {
1006 setBulkEditMode("basalam");
1007 syncTypeVisibility();
1008 syncPriceChangeVisibility();
1009 });
1010 };
1011
1012 document.addEventListener("change", (event) => {
1013 const target = event.target;
1014 if (!(target instanceof HTMLSelectElement)) {
1015 return;
1016 }
1017
1018 if (target.name === "sync_basalam_bulk_product_type_action") {
1019 syncTypeVisibility();
1020 }
1021
1022 if (target.name === "sync_basalam_bulk_price_change_action") {
1023 syncPriceChangeVisibility();
1024 }
1025 });
1026
1027 document.addEventListener("click", (event) => {
1028 const button = event.target instanceof Element
1029 ? event.target.closest("#doaction, #doaction2")
1030 : null;
1031
1032 if (!button) {
1033 return;
1034 }
1035
1036 const selectorId = button.id === "doaction2" ? "bulk-action-selector-bottom" : "bulk-action-selector-top";
1037 const actionSelect = document.getElementById(selectorId);
1038
1039 if (!(actionSelect instanceof HTMLSelectElement)) {
1040 return;
1041 }
1042
1043 if (actionSelect.value === SYNC_BASALAM_BULK_ACTION) {
1044 event.preventDefault();
1045 event.stopImmediatePropagation();
1046 openBasalamBulkEditor(actionSelect);
1047 return;
1048 }
1049
1050 if (actionSelect.value === "edit") {
1051 setBulkEditMode("default");
1052 }
1053 }, true);
1054
1055 document.addEventListener("click", (event) => {
1056 const cancelButton = event.target instanceof Element
1057 ? event.target.closest("#bulk-edit .cancel")
1058 : null;
1059
1060 if (!cancelButton) {
1061 return;
1062 }
1063
1064 setBulkEditMode("default");
1065 });
1066
1067 setBulkEditMode("default");
1068
1069 syncTypeVisibility();
1070 syncPriceChangeVisibility();
1071 };
1072
1073 initBulkEditFields();
1074
1075 var modal = document.getElementById("sync_basalam_support_modal");
1076 var btn = document.getElementById("sync_basalam_support_btn");
1077 var cancelBtn = document.getElementById("sync_basalam_cancel_btn");
1078
1079 if (btn) {
1080 btn.addEventListener("click", function () {
1081 if (modal) {
1082 modal.style.display = "flex";
1083 }
1084 });
1085 }
1086
1087 if (cancelBtn) {
1088 cancelBtn.addEventListener("click", function () {
1089 if (modal) {
1090 modal.style.display = "none";
1091 }
1092 });
1093 }
1094
1095 if (modal) {
1096 modal.addEventListener("click", function (e) {
1097 if (e.target === modal) {
1098 modal.style.display = "none";
1099 }
1100 });
1101 }
1102
1103 // Star rating functionality
1104 var currentRating = 5;
1105
1106 function updateStars(rating) {
1107 var stars = document.querySelectorAll('#basalam_rating_stars .basalam-star');
1108 stars.forEach(function(star) {
1109 var starRating = parseInt(star.getAttribute('data-rating'));
1110 if (starRating <= rating) {
1111 star.style.color = '#f5a623';
1112 } else {
1113 star.style.color = '#ddd';
1114 }
1115 });
1116 }
1117
1118 updateStars(5);
1119
1120 var starsContainer = document.getElementById('basalam_rating_stars');
1121 if (starsContainer) {
1122 starsContainer.addEventListener('mouseover', function(e) {
1123 if (e.target.classList.contains('basalam-star')) {
1124 var hoverRating = parseInt(e.target.getAttribute('data-rating'));
1125 updateStars(hoverRating);
1126 }
1127 });
1128
1129 starsContainer.addEventListener('mouseout', function() {
1130 updateStars(currentRating);
1131 });
1132
1133 starsContainer.addEventListener('click', function(e) {
1134 if (e.target.classList.contains('basalam-star')) {
1135 currentRating = parseInt(e.target.getAttribute('data-rating'));
1136 document.getElementById('sync_basalam_rating').value = currentRating;
1137 updateStars(currentRating);
1138 }
1139 });
1140 }
1141
1142 // Remind Later button
1143 var remindLaterBtn = document.getElementById('sync_basalam_remind_later_review_btn');
1144 if (remindLaterBtn) {
1145 remindLaterBtn.addEventListener('click', function() {
1146 var nonceEl = document.getElementById('sync_basalam_remind_later_review_nonce');
1147 jQuery.ajax({
1148 url: ajaxurl,
1149 type: 'POST',
1150 data: {
1151 action: 'sync_basalam_remind_later_review',
1152 _wpnonce: nonceEl ? nonceEl.value : ''
1153 },
1154 success: function() {
1155 document.getElementById('sync_basalam_like_alert').style.display = 'none';
1156 }
1157 });
1158 });
1159 }
1160
1161 // Never Remind button
1162 var neverRemindBtn = document.getElementById('sync_basalam_never_remind_review_btn');
1163 if (neverRemindBtn) {
1164 neverRemindBtn.addEventListener('click', function() {
1165 var nonceEl = document.getElementById('sync_basalam_never_remind_review_nonce');
1166 jQuery.ajax({
1167 url: ajaxurl,
1168 type: 'POST',
1169 data: {
1170 action: 'sync_basalam_never_remind_review',
1171 _wpnonce: nonceEl ? nonceEl.value : ''
1172 },
1173 success: function() {
1174 document.getElementById('sync_basalam_like_alert').style.display = 'none';
1175 }
1176 });
1177 });
1178 }
1179
1180 // Submit Review form
1181 var supportForm = document.getElementById('sync_basalam_support_form');
1182 if (supportForm) {
1183 supportForm.addEventListener('submit', function(e) {
1184 e.preventDefault();
1185 var nonceEl = document.getElementById('sync_basalam_submit_review_nonce');
1186 var ratingEl = document.getElementById('sync_basalam_rating');
1187 var commentEl = document.getElementById('sync_basalam_comment');
1188
1189 jQuery.ajax({
1190 url: ajaxurl,
1191 type: 'POST',
1192 data: {
1193 action: 'sync_basalam_submit_review',
1194 _wpnonce: nonceEl ? nonceEl.value : '',
1195 sync_basalam_rating: ratingEl ? ratingEl.value : '5',
1196 sync_basalam_comment: commentEl ? commentEl.value : ''
1197 },
1198 success: function(response) {
1199 if (response.success) {
1200 document.getElementById('sync_basalam_like_alert').style.display = 'none';
1201 if (modal) modal.style.display = 'none';
1202 } else {
1203 window.BasalamToast.error(response.data && response.data.message ? response.data.message : 'خطا در ارسال نظر');
1204 }
1205 }
1206 });
1207 });
1208 }
1209 });
1210