{"version":3,"file":"DvtoP2Sz.js","sources":["../../../../src/composables/useHelpers.ts"],"sourcesContent":["import {ref} from \"vue\";\nimport type {Property} from \"~/models/old/Property\";\nimport type {Position} from \"~/models/old/Address\";\nimport {useAddress} from \"~/composables/useAddress\";\nimport type {Car} from \"~/models/old/Car\";\nimport moment from \"moment\";\nimport {LISTINGS_SERVICE} from \"~/data/ServicesConstants\";\nimport type {User} from \"~/models/services/User\";\nimport type {Agent} from \"~/models/services/Agent\";\n\nconst topPadding = ref(120)\nconst showTab = ref(false)\n\nconst shuffleArray = (arr: T[]): T[] => {\n const shuffledArr = arr.slice(); // Crear una copia del arreglo original\n for (let i = shuffledArr.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [shuffledArr[i], shuffledArr[j]] = [shuffledArr[j], shuffledArr[i]]; // Intercambiar elementos\n }\n return shuffledArr;\n};\n\nconst formatNumberStr = (num: number): string => {\n // Si el número es menor a 1,000, devolver el número como está\n if (num < 1000) {\n return num.toString();\n }\n\n // Si el número es menor a 1,000,000, devolver el número en miles con \"K\"\n if (num < 1000000) {\n const thousands = Math.floor(num / 1000);\n return `${thousands}K`;\n }\n\n // Si el número es menor a 1,000,000,000, devolver el número en millones con \"M\"\n if (num < 1000000000) {\n const millions = Math.floor(num / 1000000);\n return `${millions}M`;\n }\n\n // Si el número es 1,000,000,000 o más, devolver el número en mil millones con \"B\"\n const billions = Math.floor(num / 1000000000);\n return `${billions}B`;\n}\n\nconst getSocialLinks = () => ref([\n {link: useNuxtApp().$socialMediaLinks.facebook, icon: 'facebook-f'},\n {link: useNuxtApp().$socialMediaLinks.instagram, icon: 'instagram'},\n {link: useNuxtApp().$socialMediaLinks.linkedin, icon: 'linkedin-in'},\n {link: useNuxtApp().$socialMediaLinks.xTwitter, icon: 'x-twitter'},\n {link: useNuxtApp().$socialMediaLinks.tiktok, icon: 'tiktok'},\n]);\n\nconst changeScreenSize = () => {\n const width = document.body.clientWidth\n topPadding.value = width <= 860 ? 70 : 120\n showTab.value = width <= 1180\n}\n\nconst parseTimeString = (timeString: string) => {\n if (timeString.includes(':') && (timeString.includes('am') || timeString.includes('pm'))) {\n // Divide la cadena en tiempo y el periodo (am/pm)\n let [time, period] = timeString.split(' ');\n\n // Divide el tiempo en horas y minutos\n let [hours, minutes] = time.split(':').map(String);\n\n return {hours, minutes, period};\n }\n return null;\n\n}\n\nconst truncateText = (htmlString: string, maxLength: number = 200): string => {\n // Crear un elemento temporal para procesar el HTML\n const tempDiv = document.createElement(\"div\");\n tempDiv.innerHTML = htmlString;\n\n // Función auxiliar para extraer el texto, añadiendo \". \" después de párrafos y divs\n function getTextContentWithPeriods(element: HTMLElement): string {\n let textContent = \"\";\n element.childNodes.forEach(node => {\n if (node.nodeType === Node.TEXT_NODE) {\n textContent += node.textContent;\n } else if (node.nodeType === Node.ELEMENT_NODE) {\n if (node.nodeName === \"P\" || node.nodeName === \"DIV\") {\n textContent += (node as HTMLElement).textContent + \". \";\n } else {\n textContent += getTextContentWithPeriods(node as HTMLElement);\n }\n }\n });\n return textContent;\n }\n\n // Obtener el texto con puntos añadidos\n const rawTextContent = getTextContentWithPeriods(tempDiv).trim();\n\n // Convertir el texto a tipo oración\n const formattedText = rawTextContent.charAt(0).toUpperCase() + rawTextContent.slice(1).toLowerCase();\n\n // Verificar si el texto necesita ser truncado\n let truncatedText = formattedText;\n if (formattedText.length > maxLength) {\n truncatedText = formattedText.substring(0, maxLength);\n // Verificar si el último carácter es un espacio\n if (truncatedText.charAt(truncatedText.length - 1) === \" \") {\n truncatedText = truncatedText.slice(0, -1) + \"...\";\n } else {\n truncatedText += \"...\";\n }\n }\n\n return truncatedText;\n}\n\nconst favDataProcess = ref([])\nconst toggleProductFav = async (status: boolean, listinID: string) => {\n const axiosRequest = await useNuxtApp().$getApi(LISTINGS_SERVICE)\n return new Promise((resolve, reject) => {\n if (!listinID || listinID == '') {\n reject()\n }\n favDataProcess.value.push(listinID)\n axiosRequest.post(`/listings/${listinID}/toggle-follow`)\n .catch(error => {\n console.error(error)\n reject(error)\n })\n .finally(() => {\n const index = favDataProcess.value.indexOf(listinID);\n if (index !== -1) {\n favDataProcess.value.splice(index, 1);\n }\n resolve(true)\n })\n\n })\n\n}\n\nconst toRadians = (degrees: number) => degrees * Math.PI / 180;\nconst toMiles = (kmDist: number) => kmDist * 0.621371\nconst distanceBtwPositions = (origin: Position, placeLocation: any) => {\n //console.log(placeLocation)\n const {lat1, lon1} = {lat1: parseFloat(`${origin.lat!}`), lon1: parseFloat(`${origin.lng!}`)}\n const {lat2, lon2} = {lat2: placeLocation.latitude, lon2: placeLocation.longitude}\n //console.log({lat1, lon1}, {lat2, lon2})\n const R = 6371; // Radio de la Tierra en kilómetros\n const dLat = toRadians(lat2 - lat1);\n const dLon = toRadians(lon2 - lon1);\n const a =\n Math.sin(dLat / 2) * Math.sin(dLat / 2) +\n Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *\n Math.sin(dLon / 2) * Math.sin(dLon / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n const distance = R * c; // Distancia en kilómetros\n\n return toMiles(distance);\n}\n\nconst cleaningPlaces = (propertyPosition: Position, places: any) => places.map(\n (el: any) => {\n return {\n type: el.types.filter((type: string) => Object.keys(useNuxtApp().$placeTypes()).includes(type))[0],\n distancia: distanceBtwPositions(propertyPosition, el.location)\n }\n });\nconst getDescriptionIARealEst = async (property: Property, places: any) => {\n const {getFullAddress} = useAddress()\n const cleanPlaces = cleaningPlaces(property.address!.position!, places)\n const data = JSON.stringify({\n nearbyPlaces: [\n ...cleanPlaces\n ],\n address: getFullAddress(property.address ?? {}),\n price: property.price,\n bathrooms: property.bathrooms,\n bedrooms: property.bedrooms,\n area: property.area,\n description: property.resume\n })\n //@ts-ignore\n const prompt = `Primero entra en modo experto en marketing, luego, quiero que me ayudes solamente con un texto de máximo 3 párrafos para vender una ${property.type?.option} con estas características: ${data}, ten en cuenta que quiero que se resalten las características de los lugares cercanos y que indique que tan cercanos están, y capte al cliente. Separa cada párrafo con un salto de línea (br). El lenguaje que debes usar debe estar adaptado a Puerto Rico y debe contener algunas palabras en inglés pero en su mayoría debe ser en español. Quiero que uses emojis. Debes usar el sistema imperial. El texto debe ser formato html, pero solo dame lo que esté dentro del body, utiliza solo elementos p, br y strong. Es importante que agregues saltos de línea y que el texto indique las distancias a los lugares cercanos, por ejemplo: a menos de una milla o a menos de x pies de distancia.`\n return await useNuxtApp().$getChatStream(prompt)\n\n}\n\nconst getDescriptionIALandLot = async (property: Property) => {\n const {getFullAddress} = useAddress()\n const data = JSON.stringify({\n address: getFullAddress(property.address ?? {}),\n price: property.price,\n area: property.area\n })\n const prompt = `Primero entra en modo experto en marketing, luego, quiero que me ayudes solamente con un texto de máximo 3 párrafos para vender un terreno con estas características: ${data}, ten en cuenta que quiero que capte al cliente. Separa cada párrafo con un salto de línea (br). El lenguaje que debes usar debe estar adaptado a Puerto Rico y debe contener algunas palabras en inglés pero en su mayoría debe ser en español. Quiero que uses emojis. Debes usar el sistema imperial. El texto debe ser formato html, pero solo dame lo que esté dentro del body, utiliza solo elementos p, br y strong. Es importante que agregues saltos de línea y que el texto indique las distancias a los pueblos o lugares cercanos, por ejemplo: a menos de una milla o a menos de x pies de distancia.`\n return await useNuxtApp().$getChatStream(prompt)\n}\nconst getDescriptionIACars = async (car: Car) => {\n const data = JSON.stringify({\n data_vin: car.vin,\n price: car.price,\n title: car.title\n })\n const prompt = `Primero entra en modo experto en marketing, luego, quiero que me ayudes solamente con un texto de máximo 3 párrafos para vender un carro con estas características: ${data}, ten en cuenta que quiero una redacción en español que venda las mejores características del carro y capte al cliente. Separa cada párrafo con un salto de línea (br). El lenguaje que debes usar debe estar adaptado a Puerto Rico y debe contener algunas palabras en inglés pero en su mayoría debe ser en español. Quiero que uses emojis. Debes usar el sistema imperial. El texto debe ser formato html, pero solo dame lo que esté dentro del body, utiliza solo elementos p, br y strong. Es importante que agregues saltos de línea. Devuélveme el html en texto plano.`\n return await useNuxtApp().$getChatStream(prompt)\n\n}\nconst getDescriptionIAAgent = async (user: User, agent: Agent) => {\n const data = JSON.stringify({user: user, agent: agent})\n const role = user.role?.includes('real_estates') ? 'Bienes Raíces' : 'Carros'\n const prompt = `Primero entra en modo experto en marketing, luego, quiero que me ayudes solamente con un texto de máximo 3 párrafos para promocionar a este agente de ${role}: ${data}, ten en cuenta que quiero una redacción en español que venda a la persona y capte al cliente. Separa cada párrafo con un salto de línea (br). El lenguaje que debes usar debe estar adaptado a Puerto Rico y debe contener algunas palabras en inglés pero en su mayoría debe ser en español. Quiero que uses emojis. Debes usar el sistema imperial. El texto debe ser formato html, pero solo dame lo que esté dentro del body, utiliza solo elementos p, br y strong. Es importante que agregues saltos de línea. Devuélveme el html en texto plano.`\n return await useNuxtApp().$getChatStream(prompt)\n\n}\n\nexport const getAnswer = async (messages: string) => {\n const {body} = await fetch(\"/api/chat\", {\n method: \"POST\",\n body: JSON.stringify({\n messages,\n }),\n });\n if (!body) throw new Error(\"Unknown error\");\n\n return body;\n};\n\nconst limitDateBeforeToday = (date: string): boolean => {\n return moment(date).isSameOrAfter(moment().add(-1, 'days'))\n}\nconst spanishLocale = {\n /* starting with Sunday */\n days: 'Domingo_Lunes_Martes_Miércoles_Jueves_Viernes_Sábado'.split('_'),\n daysShort: 'Dom_Lun_Mar_Mié_Jue_Vie_Sáb'.split('_'),\n months: 'Enero_Febrero_Marzo_Abril_Mayo_Junio_Julio_Agosto_Septiembre_Octubre_Noviembre_Diciembre'.split('_'),\n monthsShort: 'Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Sep_Oct_Nov_Dic'.split('_'),\n firstDayOfWeek: 1, // 0-6, 0 - Sunday, 1 Monday, ...\n format24h: true,\n pluralDay: 'dias'\n}\n\nconst getQRCode = async (link: string, product_type: string, product_id: string) => {\n const axiosRequest = await useNuxtApp().$getApi(LISTINGS_SERVICE)\n return axiosRequest.post('/listings/generate-qr', {\n link,\n product_type,\n product_id\n }, {\n responseType: 'blob'\n })\n}\n\nconst parseUTCDate = (dateStr: string) => {\n const [datePart, timePart, meridiem] = dateStr.split(/[\\s:]+/);\n const [month, day, year] = datePart.split('-').map(Number);\n let [hour, minute] = timePart.split(':').map(Number);\n\n // Convertir a formato 24 horas\n if (meridiem.toLowerCase() === 'pm' && hour !== 12) {\n hour += 12;\n } else if (meridiem.toLowerCase() === 'am' && hour === 12) {\n hour = 0;\n }\n\n // Crear objeto Date en UTC\n const utcDate = new Date(Date.UTC(year, month - 1, day, hour, minute));\n return utcDate;\n};\n\nconst processDownloadFile = (response: any) => {\n //console.log(response)\n const url = window.URL.createObjectURL(new Blob([response.data], {type: response.data.type}));\n const link = document.createElement('a');\n link.href = url;\n link.setAttribute('target', '_blank');\n document.body.appendChild(link);\n link.click();\n}\n\nconst formatHour = (hour: Date) => {\n return moment(hour).format('hh:mm a')\n}\n\nfunction capitalizeWords(input: string): string {\n return input\n .toLowerCase()\n .split(' ')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n\n/**\n * Convierte un arreglo de { file, title } a base64 y los almacena en localStorage.\n * Devuelve las \"keys\" (IDs) de localStorage que se usaron.\n */\nasync function storeFilesInLocalStorageWithMeta(\n items: { file: File; title: string }[]\n): Promise {\n const keys: string[] = [];\n\n // Procesamos cada item en paralelo (o secuencialmente)\n for (let i = 0; i < items.length; i++) {\n const file: any = items[i];\n\n // 1) Convertimos el File en una DataURL Base64\n const base64DataUrl = await fileToBase64(file);\n\n // 2) Estructura que guardaremos en localStorage\n const dataToStore = {\n base64: base64DataUrl, // \"data:image/png;base64,....\"\n mime: file.type, // p. ej \"image/png\"\n name: file.name // \"Mi imagen genial\"\n };\n\n // 3) Generamos una clave en localStorage, por ejemplo file_0, file_1...\n const key = `file_${i}`;\n\n // 4) Guardamos como JSON\n sessionStorage.setItem(key, JSON.stringify(dataToStore));\n\n // 5) Agregamos la clave al arreglo final\n keys.push(key);\n }\n\n return keys;\n}\n\n/**\n * Función auxiliar: convierte un File a una cadena base64 (DataURL).\n */\nfunction fileToBase64(file: File): Promise {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.readAsDataURL(file); // Lee contenido como DataURL (base64 con prefijo)\n reader.onload = () => {\n if (typeof reader.result === 'string') {\n resolve(reader.result); // p.ej. \"data:image/png;base64,iVBORw0KGgoAAAANS...\"\n } else {\n reject(new Error('No se pudo leer el archivo como texto.'));\n }\n };\n reader.onerror = (err) => reject(err);\n });\n}\n\n/**\n * Dado un arreglo de keys (IDs) en localStorage, los recupera,\n * y devuelve un arreglo de File reconstruidos.\n */\nfunction getFilesFromLocalStorage(keys: string[]): File[] {\n const resultFiles: File[] = [];\n\n for (const key of keys) {\n const rawData = sessionStorage.getItem(key);\n if (!rawData) {\n console.warn(`No se encontró nada en localStorage con la key: ${key}`);\n continue;\n }\n\n // Parseamos el JSON que guardamos (contiene { base64, mime, title })\n const {base64, mime, title} = JSON.parse(rawData) as {\n base64: string;\n mime: string;\n title: string;\n };\n\n // Separamos la parte base64 (sin \"data:xxx;base64,\")\n const base64Only = base64.split(',')[1] || base64; // seguridad\n\n // Decodificamos base64 a binario\n const byteCharacters = atob(base64Only);\n const byteArray = new Uint8Array(byteCharacters.length);\n\n for (let i = 0; i < byteCharacters.length; i++) {\n byteArray[i] = byteCharacters.charCodeAt(i);\n }\n\n // Reconstruimos el File con su mime y title\n const file = new File([byteArray], title, {type: mime});\n resultFiles.push(file);\n }\n\n return resultFiles;\n}\n\n\nexport const useHelpers = () => ({\n topPadding,\n showTab,\n getSocialLinks,\n truncateText,\n changeScreenSize,\n shuffleArray,\n favDataProcess,\n toggleProductFav,\n getDescriptionIARealEst,\n getDescriptionIACars,\n limitDateBeforeToday,\n parseTimeString,\n spanishLocale,\n getQRCode,\n processDownloadFile,\n parseUTCDate,\n getDescriptionIALandLot,\n formatNumberStr,\n formatHour,\n getDescriptionIAAgent,\n capitalizeWords,\n storeFilesInLocalStorageWithMeta,\n getFilesFromLocalStorage\n})"],"names":["topPadding","ref","showTab","shuffleArray","arr","shuffledArr","i","j","formatNumberStr","num","getSocialLinks","useNuxtApp","changeScreenSize","width","parseTimeString","timeString","time","period","hours","minutes","truncateText","htmlString","maxLength","tempDiv","getTextContentWithPeriods","element","textContent","node","rawTextContent","formattedText","truncatedText","favDataProcess","toggleProductFav","status","listinID","axiosRequest","LISTINGS_SERVICE","resolve","reject","error","index","toRadians","degrees","toMiles","kmDist","distanceBtwPositions","origin","placeLocation","lat1","lon1","lat2","lon2","R","dLat","dLon","a","c","distance","cleaningPlaces","propertyPosition","places","el","type","getDescriptionIARealEst","property","getFullAddress","useAddress","cleanPlaces","data","prompt","_a","getDescriptionIALandLot","getDescriptionIACars","car","getDescriptionIAAgent","user","agent","limitDateBeforeToday","date","moment","spanishLocale","getQRCode","link","product_type","product_id","parseUTCDate","dateStr","datePart","timePart","meridiem","month","day","year","hour","minute","processDownloadFile","response","url","formatHour","capitalizeWords","input","word","storeFilesInLocalStorageWithMeta","items","keys","file","dataToStore","fileToBase64","key","reader","err","getFilesFromLocalStorage","resultFiles","rawData","base64","mime","title","base64Only","byteCharacters","byteArray","useHelpers"],"mappings":"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"}