// import Vue from "vue"; // const crypto = require("crypto"); import exportFromJSON from "export-from-json"; // import store from "@store/store"; export const isLoginRemoved = () => process.env.VUE_APP_LOGIN_REMOVE == 1; // util to export to excel file using plugin // https://github.com/zheeeng/export-from-json // export const convertJsonToExcelUsingPlugin = async ( // data, // fileName = "download" // ) => { // // 'txt'(default), 'css', 'html', 'json', 'csv', 'xls', 'xml' // const exportType = exportFromJSON.types.xls; // const withBOM = true; // return await exportFromJSON({ data, fileName, exportType, withBOM }); // }; // util to export to excel file manually export const exportJsonToExcelManually = (JSONData, FileTitle, ShowLabel) => { //If JSONData is not an object then JSON.parse will parse the JSON string in an Object var arrData = typeof JSONData != "object" ? JSON.parse(JSONData) : JSONData; var CSV = ""; //This condition will generate the Label/Header if (ShowLabel) { var row = ""; //This loop will extract the label from 1st index of on array for (var index in arrData[0]) { //Now convert each value to string and comma-seprated row += encodeURI(index) + ","; } row = row.slice(0, -1); //append Label row with line break CSV += row + "\r\n"; } //1st loop is to extract each row for (var i = 0; i < arrData.length; i++) { var row = ""; //2nd loop will extract each column and convert it in string comma-seprated for (var index in arrData[i]) { row += '"' + arrData[i][index] + '",'; } row.slice(0, row.length - 1); //add a line break after each row CSV += row + "\r\n"; } if (CSV == "") { alert("Invalid data"); return; } //Generate a file name // application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8; // text/csv;charset=utf-8; // var csvContent = "data:text/csv;charset=utf-8,%EF%BB%BF" + encodeURI(csvContent); var filename = FileTitle; var blob = new Blob([CSV], { type: "text/csv;charset=utf-8,BOM", }); if (navigator.msSaveBlob) { // IE 10+ navigator.msSaveBlob(blob, filename); } else { var link = document.createElement("a"); if (link.download !== undefined) { // feature detection // Browsers that support HTML5 download attribute var url = URL.createObjectURL(blob); link.setAttribute("href", url); link.style = "visibility:hidden"; link.download = filename + ".csv"; document.body.appendChild(link); link.click(); document.body.removeChild(link); } } }; // util to delay promise export const wait = (ms) => { return (x) => { return new Promise((resolve) => setTimeout(() => resolve(x), ms)); }; }; // util to createObjectByNewProperties export const createObjectByNewProperties = (list, allowedProperties) => { const properties = []; list.forEach((item, index) => { const filtered = Object.keys(item) .filter((key) => allowedProperties.includes(key)) .reduce((obj, key) => { obj[key] = item[key]; return obj; }, {}); properties[index] = filtered; }); return properties; }; // util to convert digits to character export const toNumbersInCharacters = (number) => { const persianNumbers = ["۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹", "۰"]; const arabicNumbers = ["١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩", "٠"]; const englishNumbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]; const persianNumbersInCharacters = [ "یک", "دو", "سه", "چهار", "پنج", "شش", "هفت", "هشت", "نه", "صفر", ]; // only replace english number with persian number character return persianNumbersInCharacters[englishNumbers.indexOf(number)]; // convert all numbers to persian digits // return str.split("").map(c => // persianNumbersInCharacters[englishNumbers.indexOf(c)] || // persianNumbersInCharacters[englishNumbers.indexOf(c)] || c).join("") }; // util to handle if img src is not valid export const handleImageSrcOnError = ({ target }, isUserAvatar = true) => { if (isUserAvatar) target.classList.add("human-avatar"); target.classList.add("error"); }; // util to convert date to local date and time strng; export const persianDateAndTime = (stringDate, local = "fa-IR") => { let date = new Date(stringDate); let jsonDate = { weekday: { long: date.toLocaleDateString(local, { weekday: "long" }), short: date.toLocaleDateString(local, { weekday: "short" }), narrow: date.toLocaleDateString(local, { weekday: "narrow" }), }, era: { long: date.toLocaleDateString(local, { era: "long" }), short: date.toLocaleDateString(local, { era: "short" }), narrow: date.toLocaleDateString(local, { era: "narrow" }), }, timeZoneName: { long: date.toLocaleDateString(local, { timeZoneName: "long" }), short: date.toLocaleDateString(local, { timeZoneName: "short" }), }, year: { numeric: date.toLocaleDateString(local, { year: "numeric" }), "2-digit": date.toLocaleDateString(local, { year: "2-digit" }), }, month: { numeric: date.toLocaleDateString(local, { month: "numeric" }), "2-digit": date.toLocaleDateString(local, { month: "2-digit" }), long: date.toLocaleDateString(local, { month: "long" }), short: date.toLocaleDateString(local, { month: "short" }), narrow: date.toLocaleDateString(local, { month: "narrow" }), }, day: { numeric: date.toLocaleDateString(local, { day: "numeric" }), "2-digit": date.toLocaleDateString(local, { day: "2-digit" }), }, hour: { numeric: date.toLocaleTimeString(local, { hour: "numeric" }), "2-digit": date.toLocaleTimeString(local, { hour: "2-digit" }), }, minute: { numeric: date.toLocaleTimeString(local, { minute: "numeric" }), "2-digit": date.toLocaleTimeString(local, { minute: "2-digit" }), }, second: { numeric: date.toLocaleTimeString(local, { second: "numeric" }), "2-digit": date.toLocaleTimeString(local, { second: "2-digit" }), }, }; return jsonDate; }; // util to format numbers to local curency export const formatNumber = (price = "") => { return new Intl.NumberFormat("fa-IR").format(price); }; export const isValidHttpUrl = (string) => { let url; try { url = new URL(string); } catch (_) { return false; } return url.protocol === "http:" || url.protocol === "https:"; }; export const addJsCssFileToDom = (fileUrl, fileType, uuid) => { let targetElement = fileType == "js" ? "script" : fileType == "css" ? "link" : "none"; let targetAttr = fileType == "js" ? "src" : fileType == "css" ? "href" : "none"; let node = document.createElement(targetElement); node.setAttribute(targetAttr, fileUrl); node.setAttribute("id", targetElement + "-" + uuid); document.head.appendChild(node); }; export const removeJsCssFileFromDom = (fileType, uuid) => { let targetElement = fileType == "js" ? "script" : fileType == "css" ? "link" : "none"; document.getElementById(targetElement + "-" + uuid)?.remove(); }; export const clearBodyClass = (className = undefined) => { if (className) document.querySelector("html").replace(className, ""); else document.querySelector("html").removeAttribute("class"); }; export const redirectToExternalLink = (href, openInNewTab) => { if (href) { if (isValidHttpUrl(href) && openInNewTab) window.open(href, "_blank"); else if (isValidHttpUrl(href) && !openInNewTab) window.location.href = href; else if (!isValidHttpUrl(href) && openInNewTab) { if (href.includes("www.")) window.open("http://" + href, "_blank"); } else if (!isValidHttpUrl(href) && !openInNewTab) { if (href.includes("www.")) window.location.href = "http://" + href; } } }; export const extractAllQueryParams = (href) => { return new URLSearchParams(href); // return new Proxy(new URLSearchParams(href), { // get: (searchParams, prop) => searchParams.get(prop), // }); }; export const makeQueryParams = (url, searchParams) => { var query = new URLSearchParams(); // (A) URL SEARCH PARAMS OBJECT TO QUICKLY BUILD QUERY STRING Object.keys(searchParams).forEach((key) => query.append(key, searchParams[key]) ); // (B) CONVERT TO STRING, APPEND TO URL url += "?" + query.toString(); return url; }; // export const decryptData = ( // data, // key = "fTjWnZr4u7x!A%D*G-KaNdRgUkXp3s6v", // method = "AES-256-CBC", // iv = "poaskq2234??@35." // ) => { // let decipher = crypto.createDecipheriv(method, key, iv); // let decrypted = decipher.update(data, "base64", "utf8"); // let dd = decrypted + decipher.final("utf8"); // return JSON.parse(dd); // }; // util to handle response errors export const handleErrors = (error) => { return new Promise((resolve, reject) => { /* 401: The HTTP 401 Unauthorized response status code indicates that the client request has not been completed because it lacks valid authentication credentials for the requested resource. 403: The HTTP 403 Forbidden response status code indicates that the server understands the request but refuses to authorize it. 404: The HTTP 404 Not Found response status code indicates that the server cannot find the requested resource 405: The HyperText Transfer Protocol (HTTP) 405 Method Not Allowed response status code indicates that the server knows the request method, but the target resource doesn't support this method 406: Not Acceptable */ try { let res = error.response; if (res) { if (res.status === 401) { toast.add({ title: "خطا!", description: res.data.message, }); // router.push({ name: 'login' }) } else if (res.status === 403) { toast.add({ title: "خطا!", description: res.data.message, }); } else if (res.status === 404) { toast.add({ title: "خطا!", description: res.data.message, }); // router.push('/404') } else if (res.status === 405) { toast.add({ title: "خطا!", description: res.data.message, }); // router.push('/404') } else if (res.status === 406) { toast.add({ title: "خطا!", description: res.data.message, }); // router.push('/404') } else if (res.status === 500) { toast.add({ title: "خطا!", description: res.data.message ?? res.data, }); } else { toast.add({ title: "خطا!", description: res.data.message, }); } resolve(error.response); } else { let message = "خطا!!!"; // if (error) { // message = error.message ?? error; // } // else // { // message = "خطا!!!" // } reject(new Error(message)); // text: error.stack, toast.add({ title: message, }); } } catch (error) { let message = "خطا!!!"; message = error?.message ?? message; return reject(new Error(message)); } }); }; function countDownTimer(timeInSecond = 120) { var timeleft = timeInSecond; var downloadTimer = setInterval(function () { if (timeleft <= 0) { clearInterval(downloadTimer); // document.getElementById("countdown").innerHTML = "Finished"; } else { // document.getElementById("countdown").innerHTML = // timeleft + " seconds remaining"; } timeleft -= 1; }, 1000); return timeleft; } /////////////////////////////////////// ///// html functions /////////////////////////////////////// export function getSelectionHtmlRange() { var sel; if (window.getSelection) { sel = window.getSelection(); if (sel.rangeCount) { return sel.getRangeAt(0); } } else if (document.selection) { return document.selection.createRange(); } return null; } export function getSelectedHtmlInfo() { const selectRange = getSelectionHtmlRange(); if (!selectRange) return {}; // if (selectRange.startContainer !== selectRange.endContainer) { // return; // } let begin = 0; let strBegin = ""; let prevFullText = ""; if (selectRange.startOffset > 0) strBegin = selectRange.startContainer.textContent.substring( 0, selectRange.startOffset - 1 ); // برای وقتی که در تگ قبلی ، شماره کلمه انتها ذخیره شده است و نیازی به بررسی قبل از آن نیست if ( selectRange.commonAncestorContainer.previousSibling && selectRange.commonAncestorContainer.previousSibling.dataset?.end ) { begin = parseInt( selectRange.commonAncestorContainer.previousSibling.dataset.end ) + 1; begin += splitWord(strBegin).length; } else { prevFullText = getPreviousHtmlText(selectRange.startContainer, selectRange); begin += splitWord(prevFullText).length; } let selectedText = selectRange.startContainer.textContent.substring( selectRange.startOffset, selectRange.endOffset ); let end = begin + splitWord(selectedText).length - 1; /////////////////////////////////////////////////////// ///// استخراج کلمه کلیک شده و دو کلمه بعدش ///// برای حالتی که متنی انتخاب نشده و فقط کلیک شده نیاز هست let node = selectRange.startContainer; const fullText = node.textContent; const offset = selectRange.startOffset; const words = fullText.split(/\s+/); let totalChars = 0; let wordIndex = -1; let wordsClicked = ""; /// چون احتمال داره وسط کلمه کلیک شده باشه، قبل کلمه کلیک شده می ایستیم for (let i = 0; i < words.length; i++) { totalChars += words[i].length + 1; if (offset < totalChars) { wordIndex = i; break; } } if (wordIndex !== -1) { wordsClicked = words[wordIndex] + " " + (words[wordIndex + 1] || "") + " " + (words[wordIndex + 2] || ""); } /////////////////////////////////////////////////////// let info = { begin: begin, end: end, selectedText: selectedText, prevTextBegin: strBegin, texts: wordsClicked, // prevTextFull: prevFullText, }; return info; } export function getPreviousHtmlText(node, selectRange = null) { let text = ""; if (!node) return text; else if (selectRange && node == selectRange.startContainer) { if (selectRange.startOffset > 0) text = selectRange.startContainer.textContent.substring( 0, selectRange.startOffset - 1 ); // else // text = selectRange.startContainer.textContent; } else text = node.textContent; if (node.previousSibling) text = getPreviousHtmlText(node.previousSibling, null) + text; return text; } //////////////////////////////////////////////////////////////////// export function splitWord(text) { let items = text.split( /[\t\n\r\.\'\"«»\)\(\]\[\{\}\%\#\$\*\<\>\/,;،؛ \-!?:٭؟]+/ ); // let items = text.split("\t\n\r.'\"«»)(][{}%#$*<>/,;،؛ -!?:٭؟") return items; } export function normalizeText( text, options = { charArNormal: true, errorLine: true } ) { // //defualt // options = { // charArNormal: true, // errorLine: true, // alphabetsNormal: false, // emptylinesNormal: false, // hamzehNormal: false, // spaceCorrection: false, // trimLine: false // }; text = text.trim(); //اصلاح خطاهای متن در کد خط if (options?.errorLine) { text = text.replaceAll("\\n", "\n"); text = text.replaceAll("\\r", "\r"); text = replaceRegText("(\r\n)+", "\n", text); text = text.replaceAll("\r", "\n"); //شنبهها ==> شنبه‌ها //رسیدگیهای ==> رسیدگی‌های // text = replaceRegText("(ه)(ها)", /\1\2/gm, text); } // یکسان سازی اختلاف حروف کیبوردهای مختلف - کدهای مختلف ولی نمایش یکسان if (options?.alphabetsNormal) { text = replaceAlphabets(text); } //حذف خطوط و فاصله‌های خالی if (options?.emptylinesNormal) { text = replaceRegText("( )+", " ", text); text = replaceRegText("(\n)+", "\n", text); } // نرمال کردن حروف اختلافی عربی و فارسی if (options?.charArNormal) { text = text.replaceAll("ي", "ی"); text = text.replaceAll("ك", "ک"); } // پرش از اختلافات همزه‌ای if (options?.hamzehNormal) { text = replaceRegText("ئ|ﺋ", "ی", text); text = replaceRegText("ؤ|ﺅ", "و", text); text = replaceRegText("ﺔ|ۀ|ة", "ه", text); text = replaceRegText("إ|أ", "ا", text); } if (options?.dateNormal) { text = dateNormalize(text); } if (options?.spaceCorrection) { text = spaceCorrection(text); } // حذف خطوط اضافی اول و انتهای متن if (options?.trimLine) text = text.replace(/^\s+|\s+$/g, ""); text = text.trim(); return text; } //برعکس بودن تاریخ ها را درست میکند export function dateNormalize(text, forWord = false) { if (forWord) { // فرمت YYYY/MM/DD یا YYYY-MM-DD text = replaceRegText( /(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})/, (_, year, month, day) => `${day.padStart(2, "0")}/${month.padStart(2, "0")}/${year}`, text ); // // فرمت DD/MM/YYYY یا DD-MM-YYYY // text = replaceRegText( // /(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, // (_, day, month, year) => // `${year}/${month.padStart(2, "0")}/${day.padStart(2, "0")}`, // text // ); } else { // فرمت YYYY/MM/DD یا YYYY-MM-DD text = replaceRegText( /(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})/, (_, year, month, day) => `${year}/${month.padStart(2, "0")}/${day.padStart(2, "0")}`, text ); // فرمت DD/MM/YYYY یا DD-MM-YYYY text = replaceRegText( /(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, (_, day, month, year) => `${year}/${month.padStart(2, "0")}/${day.padStart(2, "0")}`, text ); } // // فرمت MM/DD/YYYY // text = replaceRegText( // /(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, // (_, month, day, year) => // `${year}/${month.padStart(2, "0")}/${day.padStart(2, "0")}`, // text // ); return text; } export function replaceAlphabets(text) { let res = text; res = res.replaceAll("\u00AD", "\u200C"); res = res.replaceAll("\u00AC", "\u200C"); // نیم اسپیس خاص res = replaceRegText("ﺁ|آ", "آ", res); res = replaceRegText("ﺎ|ٱ|ﺍ", "ا", res); // res = replaceRegText("ٲ|أ|ﺄ|ﺃ", "أ", res); res = replaceRegText("ﺈ|ﺇ", "إ", res); res = replaceRegText("ﺐ|ﺏ|ﺑ|ﺒ", "ب", res); res = replaceRegText("ﭖ|ﭗ|ﭙ|ﭘ", "پ", res); res = replaceRegText("ﭡ|ٺ|ٹ|ﭞ|ٿ|ټ|ﺕ|ﺗ|ﺖ|ﺘ", "ت", res); res = replaceRegText("ﺙ|ﺛ|ﺚ|ﺜ", "ث", res); res = replaceRegText("ﺝ|ڃ|ﺠ|ﺟ", "ج", res); res = replaceRegText("ڃ|ﭽ|ﭼ", "چ", res); res = replaceRegText("ﺢ|ﺤ|څ|ځ|ﺣ", "ح", res); res = replaceRegText("ﺥ|ﺦ|ﺨ|ﺧ", "خ", res); res = replaceRegText("ڏ|ډ|ﺪ|ﺩ", "د", res); res = replaceRegText("ﺫ|ﺬ|ذ", "ذ", res); res = replaceRegText("ڙ|ڗ|ڒ|ڑ|ڕ|ﺭ|ﺮ", "ر", res); res = replaceRegText("ﺰ|ﺯ", "ز", res); res = replaceRegText("ﮊ", "ژ", res); res = replaceRegText("ݭ|ݜ|ﺱ|ﺲ|ښ|ﺴ|ﺳ", "س", res); res = replaceRegText("ﺵ|ﺶ|ﺸ|ﺷ", "ش", res); res = replaceRegText("ﺺ|ﺼ|ﺻ|ﺹ", "ص", res); // res = replaceRegText("ﺽ|ﺾ|ﺿ|ﻀ", "ض", res); res = replaceRegText("ﻁ|ﻂ|ﻃ|ﻄ", "ط", res); res = replaceRegText("ﻆ|ﻇ|ﻈ", "ظ", res); res = replaceRegText("ڠ|ﻉ|ﻊ|ﻋ|ﻌ", "ع", res); res = replaceRegText("ﻎ|ۼ|ﻍ|ﻐ|ﻏ", "غ", res); res = replaceRegText("ﻒ|ﻑ|ﻔ|ﻓ", "ف", res); res = replaceRegText("ﻕ|ڤ|ﻖ|ﻗ|ﻘ", "ق", res); res = replaceRegText("ڭ|ﻚ|ﮎ|ﻜ|ﮏ|ګ|ﻛ|ﮑ|ﮐ|ڪ|ك", "ک", res); res = replaceRegText("ﮚ|ﮒ|ﮓ|ﮕ|ﮔ", "گ", res); res = replaceRegText("ﻝ|ﻞ|ﻠ|ڵ|ﻟ", "ل", res); // res = replaceRegText("ﻵ|ﻶ|ﻷ|ﻸ|ﻹ|ﻺ|ﻻ|ﻼ", "لا", res); // res = replaceRegText("ﻡ|ﻤ|ﻢ|ﻣ", "م", res); res = replaceRegText("ڼ|ﻦ|ﻥ|ﻨ|ﻧ", "ن", res); res = replaceRegText("ވ|ﯙ|ۈ|ۋ|ﺆ|ۊ|ۇ|ۏ|ۅ|ۉ|ﻭ|ﻮ|ؤ", "و", res); res = replaceRegText("ﻬ|ھ|ﻩ|ﻫ|ﻪ|ە|ہ", "ه", res); res = replaceRegText("ﭛ|ﻯ|ۍ|ﻰ|ﻱ|ﻲ|ں|ﻳ|ﻴ|ﯼ|ې|ﯽ|ﯾ|ﯿ|ێ|ے|ى|ي", "ی", res); res = replaceRegText("¬", "‌", res); res = replaceRegText("•|·|●|·|・|∙|。|ⴰ", ".", res); res = replaceRegText(",|٬|٫|‚|،", "،", res); res = replaceRegText("ʕ", "؟", res); res = replaceRegText("۰|٠", "0", res); res = replaceRegText("۱|١", "1", res); res = replaceRegText("۲|٢", "2", res); res = replaceRegText("۳|٣", "3", res); res = replaceRegText("۴|٤", "4", res); res = replaceRegText("۵", "5", res); res = replaceRegText("۶|٦", "6", res); res = replaceRegText("۷|٧", "7", res); res = replaceRegText("۸|٨", "8", res); res = replaceRegText("۹|٩", "9", res); res = replaceRegText("²", "2", res); res = replaceRegText("|ِ|ُ|َ|ٍ|ٌ|ً|", "", res); // res = replaceRegText("ـ", "_", res); res = replaceRegText("ـ", "-", res); // // res = replaceRegText("([\u0600-\u06FF])ـ([\u0600-\u06FF])", "\1\2", res) // حذف حروف کشیده // res = replaceRegText("([\u0600-\u06FF])ـ", "\1", res) // حذف حروف کشیده res = res.replace(/\u200C+$/, ""); res = res.trim(); return res; } export function spaceCorrection(text) { let res = text; res = replaceRegText("^(بی|می|نمی)( )", "$1‌", res); res = replaceRegText("( )(می|نمی|بی)( )", "$1$2‌", res); res = replaceRegText( "( )(هایی|ها|های|ایی|هایم|هایت|هایش|هایمان|هایتان|هایشان|ات|ان|ین|انی|بان|ام|ای|یم|ید|اید|اند|بودم|بودی|بود|بودیم|بودید|بودند|ست)( )", "‌$2$3", res ); res = replaceRegText("( )(شده|نشده)( )", "‌$2‌", res); res = replaceRegText( "( )(طلبان|طلب|گرایی|گرایان|شناس|شناسی|گذاری|گذار|گذاران|شناسان|گیری|پذیری|بندی|آوری|سازی|بندی|کننده|کنندگان|گیری|پرداز|پردازی|پردازان|آمیز|سنجی|ریزی|داری|دهنده|آمیز|پذیری|پذیر|پذیران|گر|ریز|ریزی|رسانی|یاب|یابی|گانه|گانه‌ای|انگاری|گا|بند|رسانی|دهندگان|دار)( )", "‌$2$3", res ); return res; } export function replaceRegText(pattern, replacement, text) { const regex = new RegExp(pattern, "g"); return text.replace(regex, replacement); } export function generateUID() { // I generate the UID from two parts here // to ensure the random number provide enough bits. var firstPart = (Math.random() * 46656) | 0; var secondPart = (Math.random() * 46656) | 0; firstPart = ("000" + firstPart.toString(36)).slice(-3); secondPart = ("000" + secondPart.toString(36)).slice(-3); return firstPart + secondPart; // eg : 9c8yxr } function myEncodeQuery(text) { if (!text || text == "") return ""; //text = JSON.stringify(text); let ch1 = encodeURIComponent("#"); let ch3 = encodeURIComponent("\\"); let ch4 = encodeURIComponent("&"); text = text.replaceAll("#", ch1); text = text.replaceAll("&", ch4); text = text.replaceAll("/", "\\"); text = text.replaceAll("\\", ch3); // با تبدیل نقطه مشکل نشانی درخواست در بک حل نشد //text = text.replaceAll(".", '%2E'); return text; } export function cleanTextUnpermittedChars(text) { if (!text) return ""; text = text.replaceAll("([0x0000-0x001F]|(0x007F))", ""); return text; } // utils/tree.js export function findNodeWithPath(nodes, targetId, path = []) { for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; const currentPath = [...path, i]; // ✅ Adjust this condition based on how you identify a node if (node.id === targetId) { return { node, path: currentPath }; } // Recurse into children if they exist if (node.children && node.children.length > 0) { const result = findNodeWithPath(node.children, targetId, currentPath); if (result) return result; } } return null; // Not found } export function updateNodeByPath(nodes, path, newValue) { let current = nodes; // Navigate to the parent of the target node for (let i = 0; i < path.length - 1; i++) { current = current[path[i]].children; } // Update the target node const targetIndex = path[path.length - 1]; current[targetIndex] = { ...current[targetIndex], ...newValue }; } ////////////////////////////////////////// // export { wait, handleErrors }