<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[on the code]]></title><description><![CDATA[on the code]]></description><link>https://onthecode.blog</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1750755243747/43d22693-4637-439f-af04-045dadcdbe59.png</url><title>on the code</title><link>https://onthecode.blog</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 06 Mar 2026 15:44:46 GMT</lastBuildDate><atom:link href="https://onthecode.blog/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><atom:link rel="first" href="https://onthecode.blog/rss.xml"/><item><title><![CDATA[¿Por qué todos usan TAILWIND? qué es y cómo funciona]]></title><description><![CDATA[<p>Cuando hablamos de frameworks CSS, uno de los nombres que ms resuena ltimamente es <strong>Tailwind CSS</strong>. Pero qu lo hace diferente de otras herramientas como Bootstrap? En este artculo te voy a explicar de forma sencilla por qu Tailwind ha revolucionado la forma en que diseamos interfaces web, y qu papel cumple su potente compilador <em>Just-in-Time</em>.</p>
<h2 id="heading-que-es-tailwind-css">Qu es Tailwind CSS?</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/GU4gkH1MDZw">https://youtu.be/GU4gkH1MDZw</a></div>
<p> </p>
<p>Tailwind CSS es un framework basado en <strong>clases utilitarias</strong>. Esto significa que, en lugar de darte componentes ya armados (como botones o cards), te ofrece una serie de clases, tambin llamadas <strong>utilities</strong> que pods combinar para construir tu diseo desde cero.</p>
<p>Pensalo as: si Bootstrap te da una casa ya construida, Tailwind te da los ladrillos, la madera y las herramientas para que vos la armes como quieras. Esta filosofa lo convierte en una herramienta <strong>mucho ms flexible y personalizable</strong>.</p>
<h2 id="heading-tailwind-vs-bootstrap-diferencias-clave">Tailwind vs Bootstrap: Diferencias clave</h2>
<p>Con <strong>Bootstrap</strong>, si quers una <em>card</em>, lo ms comn es ir a la documentacin, copiar el cdigo HTML de una card ya armada, y pegarlo en tu sitio. Eso funciona, pero ests importando <strong>toda la librera de Bootstrap</strong>, aunque solo uses una parte.</p>
<p>Con <strong>Tailwind</strong>, en cambio, no copis componentes prefabricados. Vos <strong>cres tus propios componentes</strong> usando clases como <code>bg-white</code>, <code>shadow-md</code>, <code>p-4</code>, etc. Cada clase hace una cosa especfica, y las combins segn tus necesidades.</p>
<p><strong>Esto te da:</strong></p>
<ul>
<li><p>Ms control sobre el diseo</p>
</li>
<li><p>Menos dependencias</p>
</li>
<li><p>Mejor rendimiento</p>
</li>
</ul>
<h2 id="heading-el-superpoder-de-tailwind-su-compilador-jit">El superpoder de Tailwind: su compilador JIT</h2>
<p>Una de las caractersticas ms poderosas de Tailwind es su <strong>compilador JIT (Just-In-Time)</strong>.</p>
<p>Este compilador analiza tu cdigo y <strong>genera nicamente el CSS necesario para las clases que ests usando</strong>. Nada ms.</p>
<p><strong>Qu significa esto?</strong></p>
<ul>
<li><p>Tu archivo CSS final es sper liviano</p>
</li>
<li><p>No se carga todo el framework, solo lo que uss</p>
</li>
<li><p>Incluso tus clases personalizadas se procesan sin problema</p>
</li>
</ul>
<p>Por ejemplo, si tens un <code>h1</code> dentro de un contenedor y le aplics clases como <code>m-5</code>, <code>text-2xl</code>, <code>font-bold</code>, el compilador solo va a generar esas clases en el CSS final. As de eficiente.</p>
<h2 id="heading-ventajas-principales-de-usar-tailwind">Ventajas principales de usar Tailwind</h2>
<ul>
<li><p><strong>Flexibilidad total</strong> para crear tu propio diseo</p>
</li>
<li><p><strong>Carga ms rpida</strong> gracias a un CSS optimizado</p>
</li>
<li><p><strong>Estilo consistente</strong> sin escribir CSS desde cero</p>
</li>
<li><p><strong>Escalable</strong> para proyectos chicos o grandes</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusin</h2>
<p>Tailwind no es solo un conjunto de clases utilitarias: es una nueva forma de pensar el diseo web.<br />Te da control, velocidad y eficiencia. Y su compilador JIT es la clave para mantener tu proyecto liviano y gil.</p>
<p>Muchas gracias y saludos!</p>
]]></description><link>https://onthecode.blog/por-que-todos-usan-tailwind-que-es-y-como-funciona</link><guid isPermaLink="true">https://onthecode.blog/por-que-todos-usan-tailwind-que-es-y-como-funciona</guid><dc:creator><![CDATA[Pablo Mchn]]></dc:creator></item><item><title><![CDATA[Primeros pasos con Supabase: creá tu primera app paso a paso]]></title><description><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/ImEnktezqKI?si=lV89qCmhuXzPKzGv">https://youtu.be/ImEnktezqKI?si=lV89qCmhuXzPKzGv</a></div>
<p> </p>
<p>Qu bueno que exista Supabase! Es genial para usar como backend en nuestros proyectos web y hacer que todo sea un poco ms fcil.</p>
<p>En este artculo te voy a mostrar, paso a paso, cmo crear una aplicacin en React que sirve como ejemplo para hacer todo lo necesario con una base de datos de Supabase: cargar datos, mostrarlos en nuestro sitio web, actualizarlos, eliminarlos y todo eso.</p>
<p>Para eso, vamos a crear una app simple que permite listar videos de youtube mediante un link a una web. Los videos se podrn marcar como vistos o no vistos (actualizar), borrarlos y todo lo necesario para aprender a usar Supabase.</p>
<p>Es un proceso simple y, en poco tiempo, vas a saber cmo utilizar Supabase en tu proyecto.</p>
<p>Vamos con el paso a paso!</p>
<h2 id="heading-primer-paso-crear-una-cuenta-en-supabase">Primer paso: Crear una cuenta en Supabase</h2>
<p>Vamos entonces al sitio de <a target="_blank" href="https://supabase.com/">Supabase</a> y crear una cuenta si es que an no lo hiciste, es gratis hacerlo y no necesitas poner datos de una tarjeta de crdito. El proceso de crear una cuenta es rpido y simple.</p>
<p><a target="_blank" href="https://supabase.com/"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750249376345/837e0420-7612-485d-8f2c-0ffda8379e38.png" alt class="image--center mx-auto" /></a></p>
<p>Ya esta lista tu cuenta? Perfecto, seguimos con el segundo paso.</p>
<h2 id="heading-segundo-paso-crear-un-proyecto-en-supabase">Segundo paso: Crear un proyecto en Supabase</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750250553822/ec9b8af0-d192-479b-a3ff-219610e03083.png" alt class="image--center mx-auto" /></p>
<p>Cuando creas tu cuenta en Supabase, lo primero que hay que hacer es crear una <strong>organizacin</strong>. Dentro de esa organizacin, hay que crear un <strong>proyecto</strong>.</p>
<p>En mi caso, la organizacin se llama <em>ondecode</em> y el proyecto lo nombr <em>video manager</em>.</p>
<p>Despus, Supabase te va a pedir que configures una contrasea segura. Esta clave es la que protege el acceso a la base de datos, as que tiene sentido usar el botn <em>"Generate a password"</em> que te ofrece la plataforma. As nos aseguramos de tener una contrasea fuerte y segura.</p>
<p>Por ltimo, hay elegir una regin. Lo ideal es seleccionar la que est ms cerca del pas en el que te encontrs, para optimizar el rendimiento.</p>
<p>Ahora s, hay que hacer clic en <strong>"Create Project"</strong>.</p>
<p>Una vez creado el proyecto, deberas poder ver dentro del Project overview las configuraciones generales, algo como esto 👇</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750253544991/a8090449-ed00-4882-a433-7dd3c3e747e6.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-tercer-paso-como-configurar-supabase-en-un-proyecto-react">Tercer paso: Cmo Configurar Supabase en un proyecto React</h2>
<p>Vamos ahora a crear el proyecto de react utilizando <a target="_blank" href="https://vite.dev/">vite</a>.</p>
<p>Para ello en tu terminal ejecuta el siguiente comando.</p>
<p><code>npm create vite@latest</code></p>
<p>Ahora vamos a ir respondiendo las preguntas para configurar el nombre, el package, el framework y la variante o lenguaje.</p>
<pre><code class="lang-bash">npm create vite@latest

  Project name:
   REACT-SUPABASE

  Package name:
   package.json

  Select a framework:
   React

  Select a variant:
   JavaScript
</code></pre>
<p>Como lenguaje opte por <strong>JavaScript</strong>, para no dejar afuera a quienes no se sienten cmodos con TypeScript.</p>
<p>Luego:</p>
<pre><code class="lang-bash">  Scaffolding project <span class="hljs-keyword">in</span> .../Desktop/REACT-SUPABASE...
  Done. Now run:

<span class="hljs-built_in">cd</span> REACT-SUPABASE
npm install
</code></pre>
<p>Una ves ejecutado el comando <code>npm install</code> ya tenemos el proyecto de React creado con sus dependencias instaladas.</p>
<p>Pero <strong>Supabase no viene incluido por defecto</strong>, as que necesitamos instalarlo manualmente con el siguiente comando:</p>
<p><code>npm install @supabase/supabase-js</code></p>
<p>Para conectar nuestra app con Supabase, agregu dos archivos al proyecto:</p>
<ul>
<li><p><code>supabase.js</code>  donde vamos a inicializar el cliente de Supabase</p>
</li>
<li><p><code>.env</code>  donde guardamos de forma segura nuestras claves de acceso</p>
</li>
</ul>
<p>As se ve la estructura bsica del proyecto: 👇</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750254531820/9b0118df-a665-49c3-94f2-f3db0f1fde8b.png" alt class="image--center mx-auto" /></p>
<p>Empecemos por el primer archivo: <code>.env</code>.</p>
<p>En este archivo vamos a guardar las claves de nuestro proyecto de Supabase, como <code>SUPABASE_URL</code> y <code>SUPABASE_KEY</code>.</p>
<p>Estas son las variables de entorno necesarias para conectar tu app con el backend de Supabase de forma segura.</p>
<p>La <code>SUPABASE_URL</code> la pods encontrar en la seccin <strong>Project Overview</strong>, justo despus de crear tu proyecto. Est identificada como <strong>PROJECT URL</strong>, hay que copiarla y pegarla en el archivo <code>.env</code>.</p>
<p>En caso de que ya no aparezca dentro de <strong>Project Overview</strong> la vas a poder encontrar en <strong>Project Settings</strong> en la opcin <strong>data API</strong>.</p>
<p><code>Archivo .env</code></p>
<pre><code class="lang-javascript">VITE_SUPABASE_URL=https:<span class="hljs-comment">//dgmtpjufuhzjznaid.supabase.co</span>
</code></pre>
<p>Ahora nos queda ir a buscar la <code>SUPABASE_KEY</code>. Para eso, vamos a <strong>Project Settings</strong> y, dentro de esa seccin, entramos a <strong>API Keys</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750255379954/548759fb-eb5a-4bbc-890f-56bb5e09e8fd.png" alt class="image--center mx-auto" /></p>
<p>Presiona <strong>"Reveal"</strong> para ver la <strong>Secret Key</strong>, y copiala en el archivo <code>.env</code>, justo debajo de la variable <code>SUPABASE_URL</code>.</p>
<p><code>Archivo .env 👇</code></p>
<pre><code class="lang-javascript">VITE_SUPABASE_URL=https:<span class="hljs-comment">//dgmtpjufuhzwjhzznaid.supabase.co</span>
VITE_SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.epc3MiOiJzdXBhYmFzZSIsInJlZiI6ImRnbXRwanVmdWh6d2poenpuYWlkIiwicm9sZSI6InNlcnZpY2Vfcm9sImlhdCITkxMCwihwIjoyMDY1ODI1OTEwfQ.wZl7L-BPJ6lD_A0dT0Ra2FKs78
</code></pre>
<p>Como estoy usando <strong>Vite</strong>, a las variables de entorno les agrego el prefijo <code>VITE_</code>.</p>
<p>Por supuesto, estas claves deben mantenerse seguras y privadas. Justamente por eso las colocamos en el archivo <code>.env</code>, que no debera compartirse ni subirse a ningn repositorio pblico.</p>
<p>En mi caso, las muestro nicamente porque se trata de un proyecto de prueba creado especficamente para este artculo, y que va a ser eliminado antes de ser publicado.</p>
<p>Ahora vamos a crear el archivo <code>supabase.js</code> usando las claves que guardamos en el archivo <code>.env</code>.</p>
<p><code>archivo supabase.js👇</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@supabase/supabase-js"</span>;

<span class="hljs-keyword">const</span> supabaseUrl = <span class="hljs-keyword">import</span>.meta.env.VITE_SUPABASE_URL
<span class="hljs-keyword">const</span> supabaseKey = <span class="hljs-keyword">import</span>.meta.env.VITE_SUPABASE_KEY

<span class="hljs-keyword">const</span> supabase = createClient(supabaseUrl,supabaseKey)

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> supabase
</code></pre>
<p>Este archivo se encarga de importar e inicializar el cliente de Supabase.</p>
<p>Una vez hecho esto, ya tendremos Supabase listo para usar en cualquier parte de nuestro proyecto React.</p>
<p>Con esto, nuestro proyecto React con Supabase est configurado y listo para seguir avanzando.</p>
<h2 id="heading-cuarto-paso-como-crear-base-de-datos-en-supabase">Cuarto paso: Cmo crear base de datos en Supabase</h2>
<p>Para crear una base de datos en Supabase, vamos al <strong>Table Editor</strong> dentro de nuestro proyecto. All podremos crear nuestras tablas de forma visual y sencilla. 👇</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750678709022/d5cf11ca-0dd2-4a73-881f-4cc98c4882b5.png" alt class="image--center mx-auto" /></p>
<p>Dentro de Table editor nos vamos a la opcin Create a Table y dentro de ella asignamos un nombre y una descripcin.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750679039510/2ae14594-166e-440d-95a4-e370a62fa906.png" alt class="image--center mx-auto" /></p>
<p>Sin cerrar esa ventana, bajamos un poco y comenzamos a agregar las columnas que formarn nuestra base de datos.</p>
<p>Por defecto ya vienen creadas dos columnas: <code>id</code> y <code>created_at</code> Esto es comn en bases de datos SQL. En el caso de Supabase se utiliza <a target="_blank" href="https://www.postgresql.org/"><strong>PostgreSQL</strong></a></p>
<p>Sumemos entonces dos columnas ms a nuestra tabla:</p>
<ul>
<li><p><code>videoLink</code> con <strong>Type: Text</strong></p>
</li>
<li><p><code>isFinished</code> con <strong>Type: Boolean</strong></p>
</li>
</ul>
<p>Estas columnas nos van a servir, por ejemplo, para guardar el enlace de un video (que luego se mostrar como un reproductor en el sitio web) y para saber si el video ya ha sido visto o no.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750680940622/3afe5c10-2d10-41ef-8dc4-15daeb4bdc54.png" alt class="image--center mx-auto" /></p>
<p>Importante: en el caso de la columna <code>videoLink</code>, entramos a sus <strong>Settings</strong> (clic en el cono de la tuerca a la derecha) y desactivamos la opcin que asigna un valor tipo <code>Null</code> por defecto cuando no se especifica ninguno.</p>
<p>Esto lo hacemos porque queremos asegurarnos de que, si no se carga un enlace de video, el campo quede vaco y no se muestre ningn reproductor por error en el sitio web.</p>
<p>Listo! Solo queda hacer clic en la opcin <strong>Save</strong>, y ya tenemos nuestra base de datos creada y lista para usar.</p>
<p>Nuestro Table Editor ahora se ve as 👇</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750681834783/6e8b9409-82bc-4afe-85fb-4f9bd68ce4d1.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-quinto-paso-como-usar-la-base-de-datos-de-supabase-desde-react">Quinto paso: Cmo Usar la base de datos de Supabase desde React</h2>
<p>Levantamos primero nuestro proyecto de React con el siguiente comando:</p>
<p><code>npm run dev</code></p>
<p>Una vez que confirmamos que el proyecto se est ejecutando correctamente en <code>http://localhost:5173</code>, vamos a limpiar el archivo <code>App.jsx</code>. Para comenzar a construir nuestra aplicacin desde cero e interactuar directamente con la base de datos que creamos en Supabase.</p>
<p>Comencemos armando la estructura 👇</p>
<p><code>Archivo App.jsx</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> supabase <span class="hljs-keyword">from</span> <span class="hljs-string">"./supabase"</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [videoRequest, setVideoRequest] = useState(<span class="hljs-string">''</span>)
  <span class="hljs-keyword">const</span> [videoList, setVideoList] = useState([])

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>VIDEO MANAGER<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
        <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"video url"</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">{videoRequest}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setVideoRequest(e.target.value)}
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>AGREGAR<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>Primero importamos Supabase e importamos un poco de CSS para darle algo de estilo. Adems, definimos dos estados (hooks) que nos van a servir para gestionar los videos:</p>
<ul>
<li><p><code>videoRequest</code>: guarda lo que el usuario escribe (la URL del video).</p>
</li>
<li><p><code>videoList</code>: almacenar la lista de videos agregados, que vamos a ir cargando desde Supabase ms adelante.</p>
</li>
</ul>
<p>Te muestro tambin unos mnimos estilos que deje en <code>App.css</code> 👇</p>
<pre><code class="lang-css"><span class="hljs-comment">/* CSS correspondiente a todos los elementos usados en el JSX del proyecto */</span>
<span class="hljs-selector-tag">body</span> {
<span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.6em</span> <span class="hljs-number">1em</span>;
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">0.5em</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ccc</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">60%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">400px</span>;
}

<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.6em</span> <span class="hljs-number">1em</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#646cff</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">transition</span>: background-color <span class="hljs-number">0.3s</span> ease;

}

<span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#4b5cd4</span>;
}

<span class="hljs-comment">/* Lista de videos */</span>
<span class="hljs-selector-tag">ul</span><span class="hljs-selector-class">.video-list</span> <span class="hljs-selector-tag">li</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">45rem</span>; 
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
}

<span class="hljs-selector-tag">ul</span><span class="hljs-selector-class">.video-list</span> <span class="hljs-selector-tag">li</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0.3rem</span> <span class="hljs-number">0.2rem</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">40rem</span>;
  <span class="hljs-attribute">font-weight</span>: bold;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
}


<span class="hljs-selector-tag">iframe</span> {
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">40rem</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">20rem</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">100%</span>;
}


<span class="hljs-selector-tag">ul</span><span class="hljs-selector-class">.video-list</span> <span class="hljs-selector-tag">li</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0.3rem</span> <span class="hljs-number">0.2rem</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.9rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">90%</span>;
}


<span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1.5rem</span>;
}
</code></pre>
<p>Ahora si, llego el momento! Vamos a crear la funcin <code>addVideo()</code>, que es el corazn de esta app. Con esta funcin vamos a insertar un nuevo dato (la URL del video) en nuestra base de datos en Supabase y luego mostrar ese video directamente en nuestro sitio web.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> supabase <span class="hljs-keyword">from</span> <span class="hljs-string">"./supabase"</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [videoRequest, setVideoRequest] = useState(<span class="hljs-string">''</span>)
  <span class="hljs-keyword">const</span> [videoList, setVideoList] = useState([])

  <span class="hljs-comment">//1. Creamos un nuevo objeto con los datos que queremos insertar en la tabla</span>
  <span class="hljs-keyword">const</span> addVideo = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> newVideo = {
      <span class="hljs-attr">videoLink</span>: videoRequest, <span class="hljs-comment">// La URL del video que viene del input</span>
      <span class="hljs-attr">isFinished</span>: <span class="hljs-literal">false</span>        <span class="hljs-comment">// Un campo extra para marcar estado</span>
    }

    <span class="hljs-comment">//2. Usamos supabase para insertar el nuevo video en la tabla 'Videos'</span>
    <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase
      .from(<span class="hljs-string">'Videos'</span>) <span class="hljs-comment">// accede a la tabla 'Videos' en la base de datos</span>
      .insert([newVideo]) <span class="hljs-comment">// inserta un nuevo registro (objeto) en la tabla</span>
      .select() <span class="hljs-comment">// despus de insertar el nuevo registro, queremos que nos devuelva los datos del registro insertado.</span>
      .single() <span class="hljs-comment">// espera solo un nico resultado (no un array), y lo devuelve como objeto</span>

    <span class="hljs-built_in">console</span>.log(newVideo)
    <span class="hljs-built_in">console</span>.log(data)

    <span class="hljs-comment">//3. manejo de errores y se agrega nuevo dato al estado local</span>
    <span class="hljs-keyword">if</span> (error) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'error al agregar video'</span>, error) <span class="hljs-comment">// Logueamos el error si algo sali mal</span>
    } <span class="hljs-keyword">else</span> {
      setVideoList([data, ...videoList]) <span class="hljs-comment">// Agregamos el nuevo video al estado local</span>
    }

    setVideoRequest(<span class="hljs-string">''</span>) <span class="hljs-comment">// Limpiamos el input</span>
  }
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>VIDEO MANAGER<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
        <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"video url"</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">{videoRequest}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setVideoRequest(e.target.value)}
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{addVideo}</span>&gt;</span>AGREGAR<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>Estudiemos un poco esta funcin <code>addVideo()</code></p>
<ol>
<li><strong>Creamos un nuevo objeto con los datos que queremos insertar en la tabla</strong></li>
</ol>
<p>Las claves <code>videoLink</code> e <code>isFinished</code> son los nombres que usamos en nuestro objeto, y coinciden exactamente con los campos que definimos en la tabla <code>Videos</code> de Supabase. De esta forma todo va a ser mas claro y ordenado.</p>
<ol start="2">
<li><strong>Usamos Supabase para insertar el nuevo video en la tabla</strong> <code>Videos</code></li>
</ol>
<p>De forma asncrona, utilizamos los mtodos que Supabase nos provee para insertar el nuevo video en la base de datos, y luego le pedimos que nos devuelva el registro insertado para mostrarlo en nuestro sitio.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">from</span>(<span class="hljs-string">'Videos'</span>)           <span class="hljs-comment">// Accedemos a la tabla 'Videos' en la base de datos  </span>
  .insert([newVideo])    <span class="hljs-comment">// Insertamos un nuevo registro (objeto) en la tabla  </span>
  .select()              <span class="hljs-comment">// Queremos que nos devuelva los datos del registro insertado  </span>
  .single()              <span class="hljs-comment">// Esperamos solo un nico resultado (no un array), y lo recibimos como objeto</span>
</code></pre>
<ol start="3">
<li><strong>Manejo de errores y actualizacin del estado local</strong></li>
</ol>
<p>Por ltimo, capturamos cualquier error que pueda ocurrir durante el proceso. Si todo sale bien, agregamos el nuevo video que recibimos de Supabase al estado local (videoList), para poder mostrarlo inmediatamente en la interfaz.</p>
<p>Finalmente, limpiamos el input para que quede vaco y listo para ingresar otro video.</p>
<p>La funcin <code>addVideo()</code> est asignada al botn AGREGAR. Para que todo esto suceda cuando el usuario presiona ese botn</p>
<p>De momento nuestro cdigo esta funcionando, si agregas un link de video en el input va a poder verlo en la base de datos de Supabase. 👇</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750846956431/0aa0e579-afea-46b3-8ffa-1395cef83f7f.png" alt class="image--center mx-auto" /></p>
<p>Cuando Supabase recibe el link que le enviamos por medio del input lo guarda en la tabla y automticamente le asigna un <strong>id</strong> nico y un campo <strong>created_at</strong> con la fecha y hora de creacin. Estos dos campos vienen por defecto cuando creamos nuestra tabla en Supabase.</p>
<p>En nuestro caso recibimos todo esa informacin en nuestra <code>data</code> y la agregamos en nuestro estado local</p>
<pre><code class="lang-javascript"> setVideoList([data, ...videoList]) <span class="hljs-comment">// Agregamos el nuevo video al estado local</span>
</code></pre>
<p>Esa es la diferencia entre <code>data</code> y <code>newVideo</code>:</p>
<ul>
<li><p><code>newVideo</code> es simplemente la informacin local que creamos antes de enviarla a Supabase.</p>
</li>
<li><p><code>data</code> es la informacin que nos devuelve Supabase despus de guardar el video, con datos adicionales como el <code>id</code> generado y el campo <code>created_at</code>.</p>
</li>
</ul>
<p>Por lo tanto, ahora simplemente nos queda <strong>mostrar los videos</strong> de forma correcta en nuestro sitio web.<br />Adems, vamos a agregar la posibilidad de <strong>actualizar su estado</strong> (<code>isFinished</code>) y tambin la opcin de <strong>eliminar el video</strong>.</p>
<p>Para eso, vamos a modificar un poco el <code>return</code> de nuestro componente y agregar algunos botones para interactuar con cada video. 👇</p>
<h2 id="heading-sexto-paso-mostrar-datos-desde-supabase-en-tu-aplicacion-react">Sexto paso: Mostrar datos desde Supabase en tu aplicacin React</h2>
<pre><code class="lang-javascript"> <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>VIDEO MANAGER<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"video url"</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{videoRequest}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setVideoRequest(e.target.value)}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{addVideo}</span>&gt;</span>AGREGAR<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>


      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"video-list"</span>&gt;</span>
        {videoList.map(video =&gt; (
          //Recorremos la lista de videos para mostrarlos

         <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{video.id}</span>&gt;</span>
           {/* iframe para mostrar el video de YouTube.
           Detecta si la URL es del tipo youtu.be o youtube.com y extrae el ID del video para incrustarlo */}
            <span class="hljs-tag">&lt;<span class="hljs-name">iframe</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">https:</span>//<span class="hljs-attr">www.youtube.com</span>/<span class="hljs-attr">embed</span>/${
              <span class="hljs-attr">video.videoLink.includes</span>('<span class="hljs-attr">youtu.be</span>/')
              ? <span class="hljs-attr">video.videoLink.split</span>('<span class="hljs-attr">youtu.be</span>/')[<span class="hljs-attr">1</span>]<span class="hljs-attr">.split</span>('?')[<span class="hljs-attr">0</span>]
              <span class="hljs-attr">:</span> <span class="hljs-attr">video.videoLink.split</span>('<span class="hljs-attr">v</span>=<span class="hljs-string">')[1]?.split('</span>&amp;')[<span class="hljs-attr">0</span>]
            }`}
          &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">iframe</span>&gt;</span>

           {/* Botn para cambiar el estado "visto" del video */}
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
               {video.isFinished ? 'VISTO' : 'MARCAR VISTO'}
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              {/* Botn para eliminar el video de la base de datos y del estado local */}
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>BORRAR<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
</code></pre>
<p><strong>Nota rapida sobre el iframe</strong></p>
<p>Para incrustar correctamente el video de YouTube, se hace necesario manejar dos tipos de URLs que los usuarios pueden copiar: la URL directa desde el navegador (<a target="_blank" href="http://youtube.com/watch?v="><code>youtube.com/watch?v=</code></a><code>...</code>) y la que se obtiene al hacer clic en el botn "Compartir" (<a target="_blank" href="http://youtu.be/"><code>youtu.be/</code></a><code>...</code>).</p>
<p>Por eso usamos mtodos como <code>.includes()</code>, <code>.split()</code> y una lgica condicional sencilla para extraer el ID del video de forma limpia. As adaptamos la URL al formato que requiere la etiqueta <code>&lt;iframe&gt;</code> y evitamos errores que puedan romper nuestra web.</p>
<p>Por ltimo, agregamos dos botones por cada video:</p>
<ul>
<li><p><code>&lt;button&gt;{video.isFinished ? 'VISTO' : 'MARCAR VISTO'}&lt;/button&gt;</code>: Este botn le permitira al usuario alternar el estado <code>isFinished</code> del video. Segn el valor de ese estado, se mostrar el texto correspondiente.</p>
</li>
<li><p><code>&lt;button&gt;BORRAR&lt;/button&gt;</code>: El boton que va a eliminar el video tanto de Supabase como del estado local.</p>
</li>
</ul>
<p>Con esto tenemos todo listo para poder visualizar los videos. en nuestra web, solo que no aun no los estamos trayendo desde la base de datos de Supabase.</p>
<p>Vamos a hacerlos ahora con un simple useEffect 👇</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//importar el useEffect</span>
<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>  

<span class="hljs-comment">//utilizamos la funcion fetchvideos dentro del useEffect</span>
useEffect(<span class="hljs-function">() =&gt;</span> {
    fetchVideos()
  }, [])

<span class="hljs-comment">//  funcion para traer los videos de suapabse a nuestra web</span>
  <span class="hljs-keyword">const</span> fetchVideos = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase <span class="hljs-comment">//de forma asyncrona caputramos la data(videos) o un posible error</span>
      .from(<span class="hljs-string">"Videos"</span>) <span class="hljs-comment">// accede a la tabla "Videos" en Supabase</span>
      .select(<span class="hljs-string">"*"</span>);  <span class="hljs-comment">// selecciona todos los registros y columnas</span>

    <span class="hljs-keyword">if</span> (error) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Error: "</span>, error);
    } <span class="hljs-keyword">else</span> {
      setVideoList(data);
    }
  };
</code></pre>
<p>La funcin <code>fetchVideos</code> accede con <code>.from</code> a la tabla <code>"Videos"</code> de la base de datos de Supabase, y con <code>.select("*")</code> trae <strong>todos los registros</strong>.<br />Luego, si no ocurre ningn error, esos datos se guardan en el estado <code>videoList</code> usando <code>setVideoList</code>.</p>
<p>Ese <code>videoList</code> es justamente lo que recorremos ms adelante con <code>.map()</code> dentro del <code>return</code>, para mostrar los videos en nuestra web.</p>
<p>Algo as se vera nuestro proyecto hasta ahora 👇</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750854999082/c2c24156-e9f3-4d53-9c7e-155c6478ef14.png" alt class="image--center mx-auto" /></p>
<p>Para mayor contexto te dejo el cdigo completo tal como lo tenemos hasta ahora.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> supabase <span class="hljs-keyword">from</span> <span class="hljs-string">"./supabase"</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>

<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [videoRequest, setVideoRequest] = useState(<span class="hljs-string">''</span>)
  <span class="hljs-keyword">const</span> [videoList, setVideoList] = useState([])

  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetchVideos()
  }, [])

  <span class="hljs-keyword">const</span> fetchVideos = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase
      .from(<span class="hljs-string">"Videos"</span>)
      .select(<span class="hljs-string">"*"</span>);

    <span class="hljs-keyword">if</span> (error) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Error: "</span>, error);
    } <span class="hljs-keyword">else</span> {
      setVideoList(data);
    }
  };


  <span class="hljs-keyword">const</span> addVideo = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> newVideo = {
      <span class="hljs-attr">videoLink</span>: videoRequest,
      <span class="hljs-attr">isFinished</span>: <span class="hljs-literal">false</span>
    }

    <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase
      .from(<span class="hljs-string">'Videos'</span>) <span class="hljs-comment">// accede a la tabla 'Videos' en la base de datos</span>
      .insert([newVideo]) <span class="hljs-comment">// inserta un nuevo registro (objeto) en la tabla</span>
      .select() <span class="hljs-comment">// despus de insertar el nuevo registro, queremos que nos devuelva los datos del registro insertado.</span>
      .single() <span class="hljs-comment">// espera solo un nico resultado (no un array), y lo devuelve como objeto</span>

    <span class="hljs-built_in">console</span>.log(newVideo)
    <span class="hljs-built_in">console</span>.log(data)

    <span class="hljs-keyword">if</span> (error) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'error al agregar video'</span>, error)
    } <span class="hljs-keyword">else</span> {
      setVideoList([data, ...videoList])
    }

    setVideoRequest(<span class="hljs-string">''</span>)
  }
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>VIDEO MANAGER<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"video url"</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{videoRequest}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setVideoRequest(e.target.value)}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{addVideo}</span>&gt;</span>AGREGAR<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>


      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"video-list"</span>&gt;</span>
        //Recorremos la lista de videos para mostrarlos

        {videoList.map(video =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{video.id}</span>&gt;</span>

              //iframe para mostrar el video de YouTube.
              //Detecta si la URL es del tipo youtu.be o youtube.com y extrae el ID del video para incrustarlo
                <span class="hljs-tag">&lt;<span class="hljs-name">iframe</span>
                  <span class="hljs-attr">src</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">https:</span>//<span class="hljs-attr">www.youtube.com</span>/<span class="hljs-attr">embed</span>/${
                  <span class="hljs-attr">video.videoLink.includes</span>('<span class="hljs-attr">youtu.be</span>/')
                  ? <span class="hljs-attr">video.videoLink.split</span>('<span class="hljs-attr">youtu.be</span>/')[<span class="hljs-attr">1</span>]<span class="hljs-attr">.split</span>('?')[<span class="hljs-attr">0</span>]
                  <span class="hljs-attr">:</span> <span class="hljs-attr">video.videoLink.split</span>('<span class="hljs-attr">v</span>=<span class="hljs-string">')[1]?.split('</span>&amp;')[<span class="hljs-attr">0</span>]
                }`}
              &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">iframe</span>&gt;</span>

                //Botn para cambiar el estado "visto" del video
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
                {video.isFinished ? 'VISTO' : 'MARCAR VISTO'}
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

                //Botn para eliminar el video de la base de datos y del estado local
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>BORRAR<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>Bueno, vamos poco a poco terminando, nos quedan simplemente dos cosas ms: Actualizar el estado del video si ya fue visto (y guardar ese cambio en Supabase), y tambin la posibilidad de eliminar videos de nuestro sitio web y de Supabase.</p>
<h2 id="heading-septimo-paso-como-actualizar-el-estado-de-un-video-en-supabase">Sptimo paso: Cmo actualizar el estado de un video en Supabase</h2>
<p>El video ya fue marcado como visto o no? Eso es algo que le tenemos que avisar a Supabase.<br />As que vamos a armar la funcin justo ac abajo 👇</p>
<pre><code class="lang-javascript">    <span class="hljs-comment">//UPDATE</span>
    <span class="hljs-keyword">const</span> toggleDone = <span class="hljs-keyword">async</span> (id, isFinished) =&gt; {
      <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabase
        .from(<span class="hljs-string">'Videos'</span>)
        .update({ <span class="hljs-attr">isFinished</span>: !isFinished })
        .eq(<span class="hljs-string">'id'</span>, id);

      <span class="hljs-keyword">if</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error actualizando video:'</span>, error);
      } <span class="hljs-keyword">else</span> {
        setVideoList(videoList.map(<span class="hljs-function"><span class="hljs-params">v</span> =&gt;</span>
          v.id === id ? { ...v, <span class="hljs-attr">isFinished</span>: !v.isFinished } : v
        ));
      }
    };

    <span class="hljs-comment">//en nuestro boton aregamos la funcion</span>

  {<span class="hljs-comment">/* Botn para cambiar el estado "visto" del video */</span>}
    &lt;button onClick={<span class="hljs-function">() =&gt;</span> toggleDone(video.id, video.isFinished)}&gt;
        {video.isFinished ? <span class="hljs-string">'VISTO'</span> : <span class="hljs-string">'MARCAR VISTO'</span>}
    &lt;/button&gt;
</code></pre>
<p>Con esta funcin toggleDone, lo que hacemos es avisarle a Supabase que el estado del video cambi (si fue visto o no).</p>
<p>Primero usamos <code>.from('Videos')</code> para decirle a Supabase en qu tabla queremos trabajar. En este caso, nuestra tabla se llama "Videos".</p>
<p>Despus viene <code>.update({ isFinished: !isFinished })</code>, que bsicamente invierte el valor actual del campo isFinished. Si estaba en true, lo pasa a false, y viceversa.</p>
<p>Con <code>.eq('id', id)</code> le indicamos exactamente qu fila (qu video) queremos actualizar. Es como decirle: "busc el video con este id y actualizalo".</p>
<p>Si todo sale bien, usamos <code>setVideoList(...)</code> para actualizar el estado local en React y que la interfaz tambin muestre el cambio sin necesidad de refrescar.</p>
<p>Por ltimo, le pasamos la funcin al botn que se encarga de actualizar el estado cuando se hace click, y le indicamos que muestre VISTO o MARCAR VISTO segn corresponda.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750857715328/320bf651-3bbb-4d33-8b05-b840c461e3d0.png" alt class="image--center mx-auto" /></p>
<p>Bueno, lo ltimo que nos queda es eliminar entonces, ya vamos terminando.</p>
<h2 id="heading-octavo-paso-como-eliminar-el-estado-de-un-video-en-supabase">Octavo paso: Cmo eliminar el estado de un video en Supabase</h2>
<pre><code class="lang-javascript"> <span class="hljs-comment">//DELETE</span>
  <span class="hljs-keyword">const</span> deleteVideo = <span class="hljs-keyword">async</span> (id) =&gt; {
    <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabase
      .from(<span class="hljs-string">'Videos'</span>)
      .delete()
      .eq(<span class="hljs-string">'id'</span>, id);

    <span class="hljs-keyword">if</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error eliminando video:'</span>, error);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-comment">// Solo actualiza el estado si la eliminacin fue exitosa</span>
      setVideoList(videoList.filter(<span class="hljs-function"><span class="hljs-params">video</span> =&gt;</span> video.id !== id));
    }
  };

 {<span class="hljs-comment">/* Botn para eliminar el video de la base de datos y del estado local */</span>}
  &lt;button onClick={<span class="hljs-function">() =&gt;</span> deleteVideo(video.id)}&gt;BORRAR&lt;/button&gt;
</code></pre>
<p>Ahora vamos con la funcin para eliminar un video. Es muy parecida a la de actualizar, pero en vez de usar <code>.update()</code>, usamos <code>.delete().</code></p>
<p>Con <code>.from('Videos')</code> le decimos a Supabase que queremos trabajar en la tabla <code>Videos</code>. Luego<code>.delete()</code> para indicarle que queremos borrar un registro de la base de datos. Y con <code>.eq('id', id)</code> especificamos cul video eliminar, usando su id.</p>
<p>Si no hay errores, actualizamos el estado local con setVideoList, pero esta vez filtrando la lista para sacar el video que borramos. As desaparece inmediatamente de la interfaz.</p>
<p>Para que el usuario pueda borrar un video, agregamos un botn con un onClick que llama a esta funcin y le pasa el id del video correspondiente.</p>
<p>Con esto entonces, ya hemos finalizado este proyecto con Supabase, quiero dejarte ahora el cdigo completo para mayor claridad 👇</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> supabase <span class="hljs-keyword">from</span> <span class="hljs-string">"./supabase"</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>

<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [videoRequest, setVideoRequest] = useState(<span class="hljs-string">''</span>)
  <span class="hljs-keyword">const</span> [videoList, setVideoList] = useState([])

  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetchVideos()
  }, [])

  <span class="hljs-keyword">const</span> fetchVideos = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase
      .from(<span class="hljs-string">"Videos"</span>)
      .select(<span class="hljs-string">"*"</span>);

    <span class="hljs-keyword">if</span> (error) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Error: "</span>, error);
    } <span class="hljs-keyword">else</span> {
      setVideoList(data);
    }
  };

    <span class="hljs-comment">//AGREGAR VIDEOS</span>
  <span class="hljs-keyword">const</span> addVideo = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> newVideo = {
      <span class="hljs-attr">videoLink</span>: videoRequest,
      <span class="hljs-attr">isFinished</span>: <span class="hljs-literal">false</span>
    }

    <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase
      .from(<span class="hljs-string">'Videos'</span>) <span class="hljs-comment">// accede a la tabla 'Videos' en la base de datos</span>
      .insert([newVideo]) <span class="hljs-comment">// inserta un nuevo registro (objeto) en la tabla</span>
      .select() <span class="hljs-comment">// despus de insertar el nuevo registro, queremos que nos devuelva los datos del registro insertado.</span>
      .single() <span class="hljs-comment">// espera solo un nico resultado (no un array), y lo devuelve como objeto</span>

    <span class="hljs-built_in">console</span>.log(newVideo)
    <span class="hljs-built_in">console</span>.log(data)

    <span class="hljs-keyword">if</span> (error) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'error al agregar video'</span>, error)
    } <span class="hljs-keyword">else</span> {
      setVideoList([data, ...videoList])
    }

    setVideoRequest(<span class="hljs-string">''</span>)
  }

    <span class="hljs-comment">//UPDATE</span>
    <span class="hljs-keyword">const</span> toggleDone = <span class="hljs-keyword">async</span> (id, isFinished) =&gt; {
      <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabase
        .from(<span class="hljs-string">'Videos'</span>) <span class="hljs-comment">// Asegurate tambin de que esta tabla se llame "Videos", no "videoTest"</span>
        .update({ <span class="hljs-attr">isFinished</span>: !isFinished })
        .eq(<span class="hljs-string">'id'</span>, id);

      <span class="hljs-keyword">if</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error actualizando video:'</span>, error);
      } <span class="hljs-keyword">else</span> {
        setVideoList(videoList.map(<span class="hljs-function"><span class="hljs-params">v</span> =&gt;</span>
          v.id === id ? { ...v, <span class="hljs-attr">isFinished</span>: !v.isFinished } : v
        ));
      }
    };

  <span class="hljs-comment">//DELETE</span>
  <span class="hljs-keyword">const</span> deleteVideo = <span class="hljs-keyword">async</span> (id) =&gt; {
    <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabase
      .from(<span class="hljs-string">'Videos'</span>)
      .delete()
      .eq(<span class="hljs-string">'id'</span>, id);

    <span class="hljs-keyword">if</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error eliminando video:'</span>, error);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-comment">// Solo actualiza el estado si la eliminacin fue exitosa</span>
      setVideoList(videoList.filter(<span class="hljs-function"><span class="hljs-params">video</span> =&gt;</span> video.id !== id));
    }
  };
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>VIDEO MANAGER<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"video url"</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{videoRequest}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setVideoRequest(e.target.value)}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{addVideo}</span>&gt;</span>AGREGAR<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>


      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"video-list"</span>&gt;</span>
        {videoList.map(video =&gt; (
          //Recorremos la lista de videos para mostrarlos

         <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{video.id}</span>&gt;</span>
           {/* iframe para mostrar el video de YouTube.
           Detecta si la URL es del tipo youtu.be o youtube.com y extrae el ID del video para incrustarlo */}
            <span class="hljs-tag">&lt;<span class="hljs-name">iframe</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">https:</span>//<span class="hljs-attr">www.youtube.com</span>/<span class="hljs-attr">embed</span>/${
              <span class="hljs-attr">video.videoLink.includes</span>('<span class="hljs-attr">youtu.be</span>/')
              ? <span class="hljs-attr">video.videoLink.split</span>('<span class="hljs-attr">youtu.be</span>/')[<span class="hljs-attr">1</span>]<span class="hljs-attr">.split</span>('?')[<span class="hljs-attr">0</span>]
              <span class="hljs-attr">:</span> <span class="hljs-attr">video.videoLink.split</span>('<span class="hljs-attr">v</span>=<span class="hljs-string">')[1]?.split('</span>&amp;')[<span class="hljs-attr">0</span>]
            }`}
          &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">iframe</span>&gt;</span>

           {/* Botn para cambiar el estado "visto" del video */}
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> toggleDone(video.id, video.isFinished)}&gt;
                {video.isFinished ? 'VISTO' : 'MARCAR VISTO'}
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              {/* Botn para eliminar el video de la base de datos y del estado local */}
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> deleteVideo(video.id)}&gt;BORRAR<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>Muchas gracias por leerme y espero que te haya servido!</p>
<p>Saludos!</p>
<p>Pablo.</p>
]]></description><link>https://onthecode.blog/primeros-pasos-con-supabase-crea-tu-primera-app-paso-a-paso</link><guid isPermaLink="true">https://onthecode.blog/primeros-pasos-con-supabase-crea-tu-primera-app-paso-a-paso</guid><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Pablo Mchn]]></dc:creator></item><item><title><![CDATA[Cómo integrar modelos 3D en tu sitio web utilizando sólo HTML y CSS]]></title><description><![CDATA[<p>En este articulo quiero mostrarte como visualizar elementos 3d en tu sitio web de una forma muy simple.</p>
<p>Tengo un video al respecto, si te interesa podes verlo, y si no tambin voy a ir a paso a paso en este articulo.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=mSB2scT6fTY">https://www.youtube.com/watch?v=mSB2scT6fTY</a></div>
<p> </p>
<p>Vamos con el paso a paso:</p>
<h2 id="heading-1-como-conseguir-un-modelo-3d-para-tu-web">1. Cmo conseguir un modelo 3d para tu web</h2>
<p>La internet esta llena de modelos 3d para descargar de forma gratuita o de pago. Un lugar muy conocido es <a target="_blank" href="https://sketchfab.com/feed">sketchfab</a></p>
<p><a target="_blank" href="https://sketchfab.com/feed"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749569447108/e3857e65-af8b-4b8e-b590-a3e1d1efe322.png" alt class="image--center mx-auto" /></a></p>
<p>yo encontr un dragon 3D muy bueno y me lo pude descargar de forma gratuita (agradecimientos al creador del modelo en el video)</p>
<p>Te recomiendo descargar con el formato en formato .gltf o .glb</p>
<p>Si descargas .glb se te va a descargar directamente un archivo con la extensin .glb. En cambio con .gltf se te va a descargar una carpeta con varios archivos dentro, hay que descomprimirla. Si bien el importante es es el scene.gltf no elimines ningn archivo, dependen uno de otro y esta bien dejarlos dentro de la carpeta.</p>
<p>Una vez que tenes tu modelo 3D vamos al paso dos:</p>
<h2 id="heading-2-como-insertar-un-modelo-3d-en-el-html">2. Cmo insertar un modelo 3D en el HTML</h2>
<p>No existe por default una etiqueta HTML que pueda cargar elementos 3D en la web, sera un sueo, pero lo bueno es que google se encargo de solucionar esto creando una poderosa etiqueta web llamada <a target="_blank" href="https://modelviewer.dev/">model-viewer</a></p>
<h2 id="heading-que-es-model-viewer">Qu es model-viewer?</h2>
<p><a target="_blank" href="https://modelviewer.dev/"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749569515873/3571ce0d-89fc-4b5b-83cf-fbbef5feaeeb.png" alt class="image--center mx-auto" /></a></p>
<p><code>&lt;model-viewer&gt;</code> Es un componente web que te permite incrustar modelos 3D directamente en tu HTML sin necesidad de libreras como Three.js. Es compatible con los principales navegadores modernos y soporta formatos como .glb y .gltf.</p>
<p>Como dice la documentacin en la pagina de <a target="_blank" href="https://modelviewer.dev/">model-viewer</a> hay que importarse el script con el componente model viewer y luego de ello ya se puede usar <code>&lt;model-viewer&gt;</code> como cualquier otro elemento de HTML.</p>
<p>Hay que tener en cuenta que como estamos trabajando sin ningun framework, solo con un poco de HTML. Entonces tenemos que visualizar nuestro proyecto levantando un servidor, sin un servidor esto no funciona. La extension <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ritwickdey">live server</a> es mas que suficiente.</p>
<p>Entoces:</p>
<h2 id="heading-3-insertar-el-modelo-3d-en-el-html-con-model-viewer">3. Insertar el modelo 3D en el HTML con model-viewer</h2>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Document<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Use it like any other HTML element --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">model-viewer</span>
    <span class="hljs-attr">src</span>=<span class="hljs-string">"shenron_dragon_ball/scene.gltf"</span>
    <span class="hljs-attr">alt</span>=<span class="hljs-string">"avatar"</span>
    <span class="hljs-attr">shadow-intensity</span>=<span class="hljs-string">"1"</span>
    <span class="hljs-attr">camera-controls</span>
     &gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">model-viewer</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Import the component --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://ajax.googleapis.com/ajax/libs/model-viewer/4.0.0/model-viewer.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>El elemento <code>&lt;model-viewer&gt;</code> tiene varios atributos y propiedades que se pueden utilizar. Se pueden encontrar dentro del apartado de <a target="_blank" href="https://modelviewer.dev/docs/index.html">API REFERENCE</a> de la documentacin.</p>
<p>Pero los mas elementales para agregar casi de forma obligatoria son los siguientes</p>
<p><code>src</code> Para poner la ruta de nuestro archivo 3d, si descargaste glb sera simplemente el archivo. Si descargaste gltf entonces la ruta sera a la carpeta descargada y dentro de ella al archivo scene.gltf</p>
<p>Hay que tener mucho cuidado de no fallar con la ruta del archivo 😅</p>
<p><code>shadow-intensity</code> Es quien controla la opacidad de la sombra del modelo 3d, si por ejemplo dejaras el valor en 0, debera desactivar la sombra por completo.</p>
<p><code>camara-controls</code> Le permiten al usuario mover y controlar al modelo 3d</p>
<p>Pero hay muchos otros que te van a encantar si te da ganas de probarlos :) bscalos aca: <a target="_blank" href="https://modelviewer.dev/docs/index.html">API REFERENCE</a></p>
<p>Tambin al model-viewer se le pueden aplicar estilos sin problemas, a modo de ejemplo:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
   <span class="hljs-selector-tag">model-viewer</span> {
       <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
       <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
   }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<h2 id="heading-comentarios-finales">Comentarios finales</h2>
<p>Queda marcar que model-viewer es compatible con las ltimas versiones principales de todos los navegadores.</p>
<p>Los nicos limites estn en si lo queres utilizar en modelos de realidad aumentada especialmente con los navegadores safari y mozilla. Pero con 3D todo funciona de maravilla!</p>
<p>Eso es todo y muchas gracias!</p>
<p>Saludos, Pablo</p>
]]></description><link>https://onthecode.blog/como-integrar-modelos-3d-en-tu-sitio-web-utilizando-solo-html-y-css</link><guid isPermaLink="true">https://onthecode.blog/como-integrar-modelos-3d-en-tu-sitio-web-utilizando-solo-html-y-css</guid><category><![CDATA[3d]]></category><category><![CDATA[HTML tags ]]></category><category><![CDATA[CSS]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[spanish]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Pablo Mchn]]></dc:creator></item><item><title><![CDATA[Cómo integrar Mercado Pago Checkout Pro con Next.js paso a paso]]></title><description><![CDATA[<p>En este tutorial vamos a armar un mini proyecto con Next.js para integrar Mercado Pago usando Checkout Pro. Vas a aprender a crear un endpoint API en el backend que genere la preferencia de pago, y un frontend para enviar los datos del producto y as poder armar esa preferencia.</p>
<p>Record que cuando hablamos de preferencia nos referimos a la info bsica del producto que quers vender: nombre, precio, cantidad y dems.</p>
<p>Primero en tu proyecto de next js hay que instalar el sdk de mercado pago corriendo el siguiente comando:</p>
<p><code>npm install @mercadopago/sdk-react</code></p>
<p>Una vez hecho eso te voy a mostrar los archivos que necesitas crear y cmo organizarlos dentro del sistema de rutas.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749461665103/1b9fa6d4-d66c-4b4d-b882-cd1948932b00.png" alt="Image description" /></p>
<p>Ac hay tres archivos importantes que vamos a usar:</p>
<ol>
<li><p>global.d.ts, donde vamos a agregar unas configuraciones mnimas para que todo funcione bien con TypeScript y mercadopago.</p>
</li>
<li><p>page.tsx, que es el archivo principal del frontend en Next.js donde vamos a mostrar el botn de pago.</p>
</li>
<li><p>route.ts, que va en la ruta api/mercadopago/route.ts y se encarga de la lgica del backend y del armado de la preferencia.</p>
</li>
</ol>
<h2 id="heading-1-archivo-globaldts">1) Archivo global.d.ts</h2>
<p>Dentro de este archivo hay que poner esta simple linea</p>
<p><code>declare module 'mercadopago';</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749461666258/5e553e04-57d8-4f91-90c4-ac906ada51dc.png" alt="Image description" /></p>
<p>El archivo <code>global.d.ts</code> con <code>declare module 'mercadopago';</code> le indica a TypeScript que existe un mdulo llamado 'mercadopago', permitiendo importar y usar esa librera sin errores de tipado.</p>
<h2 id="heading-2-archivo-pagetsx-el-frontend">2) Archivo page.tsx: El Frontend</h2>
<p>Este es el archivo principal de nextjs. Lo vamos a utilizar para construir el frontend que mostrar un botn de pago de Mercado Pago, generando la preferencia de pago con los datos de nuestro producto.</p>
<p>El cdigo seria algo como esto 👇</p>
<pre><code class="lang-javascript"><span class="hljs-string">'use client'</span>;

<span class="hljs-keyword">import</span> { initMercadoPago, Wallet } <span class="hljs-keyword">from</span> <span class="hljs-string">'@mercadopago/sdk-react'</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

initMercadoPago(<span class="hljs-string">'public_key'</span>, { <span class="hljs-attr">locale</span>: <span class="hljs-string">'es-AR'</span> });

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ClientWallet</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [preferenceId, setPreferenceId] = useState&lt;string | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/mercadopago'</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
      <span class="hljs-attr">headers</span>: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
        <span class="hljs-attr">title</span>: <span class="hljs-string">'producto con next'</span>,
        <span class="hljs-attr">price</span>: <span class="hljs-number">1000</span>,
        <span class="hljs-attr">quantity</span>: <span class="hljs-number">1</span>,
      }),
    });

    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> res.json();
    setPreferenceId(data.id);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>Pagar<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      {preferenceId &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">Wallet</span> <span class="hljs-attr">initialization</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">preferenceId</span> }} /&gt;</span>}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>vamos a enternder un poco que es lo que estamos haciendo en este frontend</p>
<h2 id="heading-use-client">use client</h2>
<p>en la primer linea con 'use client' se convierte el componente en client-side, y eso es clave porque usamos useState para manejar cundo mostrar el botn de Mercado Pago.</p>
<h2 id="heading-imports">imports</h2>
<p>lo siguiente es importar las cosas que necesitamos de mercado pago como el <code>initMercadoPago, Wallet</code> y tambien el <code>useState</code> de React.</p>
<h2 id="heading-inicializacion-del-sdk">Inicializacin del SDK</h2>
<p>Llamamos a initMercadoPago con nuestra API_KEY(que hay que conseguirla desde el panel de mercadoPago) y la configuracin regional. Esto prepara todo para que el SDK funcione correctamente en nuestra app.</p>
<h2 id="heading-preferenceid">preferenceId</h2>
<p>Creamos un estado con useState para guardar el id de la preferencia. Cuando enviamos la informacin de nuestro producto al backend, Mercado Pago toma esos datos y genera una preferencia de pago. A cambio, nos devuelve un id nico que representa esa preferencia.</p>
<p>Ese id es clave: es el que usamos cuando queremos mostrar el botn de pago con Checkout Pro, y le dice a Mercado Pago qu producto mostrar, con qu precio y cantidad.</p>
<h2 id="heading-funcion-handleclick">Funcin handleClick</h2>
<p>En este funcion hacemos un simple POST a nuestra api para enviarlos los datos de nuestro producto, para ello dentro del body de nuestro POST enviamos el title (nombre del producto), su precio y tambien su cantidad. Hay mas cosas que se podrian enviar al backend para que arme la preferencia pero estas son las cosas minimas que mercado pago necesita.</p>
<p>Por ultimo en la constante data guardamos la respuesta que nos devuelve el backend(el preference id de nuestor producto) y lo guardamos en nuestro estado.</p>
<h2 id="heading-renderizado-condicional-del-boton-de-pago">Renderizado condicional del botn de pago</h2>
<p>Si existe un preferenceId, mostramos el componente del SDK de Mercado Pago, que renderiza automticamente el botn de pago con todos los datos cargados.</p>
<p>Este componente es simple, pero hace todo lo necesario: conecta el frontend con el backend, y con Mercado Pago.</p>
<ol start="3">
<li>Archivo route.ts: El Backend</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { NextRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;
<span class="hljs-keyword">import</span> { MercadoPagoConfig, Preference } <span class="hljs-keyword">from</span> <span class="hljs-string">'mercadopago'</span>;

<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> MercadoPagoConfig({
  <span class="hljs-attr">accessToken</span>: <span class="hljs-string">'acces_token'</span>,
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">POST</span>(<span class="hljs-params">request: NextRequest</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> body = <span class="hljs-keyword">await</span> request.json();

    <span class="hljs-keyword">const</span> preferenceData = {
      <span class="hljs-attr">items</span>: [
        {
          <span class="hljs-attr">title</span>: body.title,
          <span class="hljs-attr">quantity</span>: <span class="hljs-built_in">Number</span>(body.quantity),
          <span class="hljs-attr">unit_price</span>: <span class="hljs-built_in">Number</span>(body.price),
          <span class="hljs-attr">currency_id</span>: <span class="hljs-string">'ARS'</span>,
        },
      ],
      <span class="hljs-attr">back_urls</span>: {
        <span class="hljs-attr">success</span>: <span class="hljs-string">'https://www.youtube.com/@onthecode'</span>,
        <span class="hljs-attr">failure</span>: <span class="hljs-string">'https://www.youtube.com/@onthecode'</span>,
        <span class="hljs-attr">pending</span>: <span class="hljs-string">'https://www.youtube.com/@onthecode'</span>,
      },
      <span class="hljs-attr">auto_return</span>: <span class="hljs-string">'approved'</span>,
    };

    <span class="hljs-keyword">const</span> preference = <span class="hljs-keyword">new</span> Preference(client);
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> preference.create({ <span class="hljs-attr">body</span>: preferenceData });

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">id</span>: result.id }), {
      <span class="hljs-attr">status</span>: <span class="hljs-number">200</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
      },
    });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error al crear la preferencia:'</span>, error);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">error</span>: <span class="hljs-string">'Error al crear la preferencia :('</span> }), {
      <span class="hljs-attr">status</span>: <span class="hljs-number">500</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
      },
    });
  }
}
</code></pre>
<h2 id="heading-inicializacion-del-cliente-de-mercado-pago">Inicializacin del cliente de Mercado Pago</h2>
<p>Usamos MercadoPagoConfig para crear una instancia del cliente, pasndole nuestro accessToken (la clave secreta que obtens desde tu cuenta de Mercado Pago). Con eso ya podemos hacer llamadas seguras al servicio desde el backend.</p>
<h2 id="heading-funcion-post">Funcin POST</h2>
<p>Esta funcin se activa cuando el frontend hace una peticin a /api/mercadopago. Recibimos los datos del producto desde el cuerpo del request: ttulo, precio y cantidad.</p>
<h2 id="heading-armado-de-la-preferencia">Armado de la preferencia</h2>
<p>Con esos datos, creamos un objeto llamado preferenceData. Ac le pasamos todo lo que necesita Mercado Pago para armar el checkout:</p>
<p>Los items (producto, precio, cantidad, moneda).</p>
<p>Las back_urls, que son las URLs adonde redirigir al usuario despus del pago (sea exitoso, fallido o pendiente).</p>
<p>Y auto_return: 'approved', que hace que el usuario vuelva automticamente cuando el pago se aprueba.</p>
<h2 id="heading-creacion-de-la-preferencia">Creacin de la preferencia</h2>
<p>Con new Preference(client).create(...) mandamos los datos a Mercado Pago. Si todo sale bien, nos devuelve un id, que es la preferencia de pago ya lista.</p>
<h2 id="heading-respuesta-al-frontend">Respuesta al frontend</h2>
<p>Devolvemos ese id al frontend en formato JSON. Con eso, el botn de pago ya sabe qu mostrar.</p>
<h2 id="heading-manejo-de-errores">Manejo de errores</h2>
<p>Si algo sale mal, lo mostramos en consola y devolvemos una respuesta con error. As evitamos que la app se rompa sin explicacin.</p>
<p>Con esto ya deberamos tener lista la pasarela de pago con Checkout Pro, usando los datos de nuestro producto. Al hacer clic en el botn "Pagar", se genera la preferencia y se renderiza automticamente el botn de Mercado Pago.</p>
<p>Al presionar ese botn, nos lleva directo al flujo de pago, donde el usuario va a ver el producto con su precio, cantidad y podr completar la compra.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749461667392/a299652d-5662-4a5a-9e41-8d67222aca42.png" alt="Image description" /></p>
<p>Antes de cerrar, no quiero dejar de recomendarte un video que te puede ayudar mucho a configurar el ambiente de pruebas de Mercado Pago. En ese video te muestro cmo crear tu app desde el panel de desarrollador, cmo generar las credenciales necesarias (la public_key para el frontend y la access_token o secret_key para el backend), y tambin cmo crear cuentas de prueba para simular pagos.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=gCcCicCDJgo&amp;t=429s">https://www.youtube.com/watch?v=gCcCicCDJgo&amp;t=429s</a></div>
<p> </p>
<p>tambin te dejo link al cdigo completo en github</p>
<p>Me dejarias una estrella en el repo? 😊 <a target="_blank" href="https://github.com/pab-mchn/Mercado-Pago-Next.js">Repositorio en Github</a></p>
<p>Muchas Gracias</p>
]]></description><link>https://onthecode.blog/como-integrar-mercado-pago-checkout-pro-con-nextjs-paso-a-paso</link><guid isPermaLink="true">https://onthecode.blog/como-integrar-mercado-pago-checkout-pro-con-nextjs-paso-a-paso</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[spanish]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Pablo Mchn]]></dc:creator></item><item><title><![CDATA[Append vs AppendChild en Javascript ¿ Cuál utilizar ?]]></title><description><![CDATA[<p>No comprendo por que usas append y no appendChild.</p>
<p>Hace poco recib este comentario en uno de mis videos de YouTube en donde muestro como ir paso a paso creando la lgica de un E-commerce con JavaScript.</p>
<p>Aqu el video para quien le interese:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/qSkXVDZwQ2I">https://youtu.be/qSkXVDZwQ2I</a></div>
<p> </p>
<p>En verdad esto me motivo a escribir este articulo para explicar la diferencia entre ambos y comentar cual es conveniente utilizar.</p>
<h2 id="heading-que-son-append-y-appendchild">Qu son append y appendChild?</h2>
<p>Append y appendChild en JavaScript son metodos para manipular el DOM (es decir: el Document Objet Model). Ambos tienen la facultad de agregar elementos al DOM pero tienen enfoques ligeramente diferentes.</p>
<h2 id="heading-el-metodo-appendchid">El mtodo appendChid</h2>
<p>Su tarea principal es agregar un nico nodo como hijo al final de otro nodo existente.</p>
<p>Para utilizarlo, primero hay que seleccionar el nodo al que deseas agregar un hijo y luego llamar a appendChild.</p>
<h2 id="heading-un-ejemplo-con-appendchild">Un ejemplo con appendChild()</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> parent = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"parentElement"</span>);
<span class="hljs-keyword">const</span> child = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
parent.appendChild(child);
</code></pre>
<p>Este cdigo va a agregar elemento child al final del elemento parent.</p>
<p>En resumen, appendChild sirve para agregar un solo nodo como hijo al final de otro nodo.</p>
<h2 id="heading-el-metodo-append">El mtodo append</h2>
<p>Con append, se puede agregar uno o varios nodos al final de un elemento especfico, se van a ir agregando en el orden en que en se proporcionan.</p>
<h2 id="heading-un-ejemplo-con-append">Un ejemplo con append()</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> parent = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"parentElement"</span>);
<span class="hljs-keyword">const</span> child1 = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
<span class="hljs-keyword">const</span> child2 = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"span"</span>);
parent.append(child1, child2);
</code></pre>
<p>Este cdigo agrega el elemento child1 seguido por el elemento child2 al final del elemento parent.</p>
<p>Entonces, append es ms verstil y permite agregar mltiples nodos en una sola llamada, lo que puede simplificar la manipulacin del DOM.</p>
<h2 id="heading-diferencias-entre-append-y-appendchild">Diferencias entre append y appendChild</h2>
<p>Comencemos con la primer diferencia importante</p>
<ol>
<li>appendChild() agrega un solo nodo / append(), agrega uno o varios nodos.</li>
</ol>
<p>Ademas con append() se pueden agregar strings. Esto no es posible con appendChild() ya que este solo acepta nodos</p>
<p>Ejemplo:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> parent = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"parentElement"</span>);
parent.append(<span class="hljs-string">"soy un texto"</span>);
</code></pre>
<p>En este caso va a funcionar ya que append() acepta el agregar texto.</p>
<p>Seguimos:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> parent = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"parentElement"</span>);
parent.appendChild(<span class="hljs-string">"soy un texto"</span>);
</code></pre>
<p>En este no va a funcionar como se espera, porque el mtodo appendChild() solo acepta agregar un nodo y no permite agregar texto</p>
<p>Entonces segunda diferencia importante:</p>
<ol start="2">
<li>appendChild() no permite agregar texto, / append() si permite agregar texto.</li>
</ol>
<h2 id="heading-conclusion">Conclusin:</h2>
<p>appendChild() agrega un solo nodo y no permite agregar texto. append() agrega uno o varios nodos y si permite agregar texto.</p>
<h2 id="heading-cual-utilizar">Cul utilizar?</h2>
<p>En mi caso prefiero utilizar append() porque es mas moderno y es una opcin ms verstil, ya que te permite agregar mltiples nodos en una sola llamada y acepta tambin pasarle texto.</p>
<p>Pero si estas buscando agregar un solo nodo appendChild() es suficiente.</p>
<p>En mi caso, me acostumbre a utilizar siempre directamente append().</p>
<p>Bueno, espero que esto te haya servido y que la pasen bien!</p>
<p>Saludos,</p>
<p>Pablo.</p>
]]></description><link>https://onthecode.blog/append-vs-appendchild-en-javascript-cual-utilizar</link><guid isPermaLink="true">https://onthecode.blog/append-vs-appendchild-en-javascript-cual-utilizar</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[spanish]]></category><dc:creator><![CDATA[Pablo Mchn]]></dc:creator></item><item><title><![CDATA[Creando un filtro de busqueda con Javascript]]></title><description><![CDATA[<p><em>Este artculo fue publicado originalmente el</em> <strong><em>13 de marzo de 2024</em></strong> <em>en mi blog anterior, el cual ya ha sido eliminado.</em></p>
<p>Vamos a crear paso a paso un filtro de bsqueda con JavaScript. La intencin es compartir el cdigo con explicaciones debajo para que puedas copiarlo e ir probando el proyecto en tu propio editor de cdigo.</p>
<p>Antes de comenzar te dejo el video de este articulo.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=1-MDMPI6vro&amp;t=78s">https://www.youtube.com/watch?v=1-MDMPI6vro&amp;t=78s</a></div>
<p> </p>
<p>No te olvides de suscribirte a mi canal, subo contenido de programacin regularmente.</p>
<h2 id="heading-1-armando-la-estructura-html">1 - Armando la estructura HTML</h2>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"styles.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Document<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"search-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"searchInput"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"buscar pas"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"resultsList"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"results-list"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"noResults"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"no-results"</span>&gt;</span>No se encontraron resultados.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"app.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>En el HTML tenemos nicamente un</p>
<p>contenedor, dentro de el colocamos un en donde el usuario va a escribir lo que desea buscar y una etiqueta <code>&lt;ul&gt;</code>, en donde luego le vamos a insertar etiquetas <code>&lt;li&gt;</code>. Armando de esta forma una lista con los resultados de la bsqueda del usuario.</p>
<p>Por ultimo, tenemos una etiqueta <code>&lt;p&gt;</code> a esta etiqueta la vamos a mostrar nicamente si no hay resultados que mostrarle al usuario.</p>
<p>Cada una de estas etiquetas tiene una clase para darle estilos y un ID para asignarle funcionalidad en un futuro con javascript.</p>
<h2 id="heading-2-aplicando-estilos-css">2 - Aplicando estilos CSS</h2>
<pre><code class="lang-css"><span class="hljs-selector-class">.search-container</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"text"</span>]</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ddd</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">outline</span>: none;
}

<span class="hljs-selector-class">.results-list</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">list-style-type</span>: none;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">22px</span>;
}

<span class="hljs-selector-class">.results-list</span> <span class="hljs-selector-tag">li</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">4px</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">4px</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-class">.no-results</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#666</span>;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">display</span>: none;
}
</code></pre>
<p>Aplicamos unos simples estilos a las clases de nuestra estructura HTML para dejar el contenido ordenado, estilamos tambin las futuras etiquetas <code>&lt;li&gt;</code> que vamos a incluir con javascript con los resultados para mostrarle al usuario y una clase no-results, que en el fututo representar el estilo de un mensaje de aviso en el caso que no se encuentren resultados.</p>
<h2 id="heading-3-funcionalidad-con-javascript">3 - Funcionalidad con Javascript</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> countries = [
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Argentina"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Bolivia"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Brasil"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Chile"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Colombia"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Ecuandor"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Mexico"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Panama"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Paraguay"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Peru"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Uruguay"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Venezuela"</span> },
];

<span class="hljs-keyword">const</span> searchInput = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"searchInput"</span>);
<span class="hljs-keyword">const</span> resultList = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"resultsList"</span>);
<span class="hljs-keyword">const</span> noResults = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"noResults"</span>);

<span class="hljs-keyword">const</span> handleSearch = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> searchTerm = searchInput.value.toLowerCase();
  <span class="hljs-keyword">const</span> filteredCountries = countries.filter(<span class="hljs-function">(<span class="hljs-params">country</span>) =&gt;</span> country.name.toLowerCase().startsWith(searchTerm));

  resultList.innerHTML = <span class="hljs-string">""</span>;

  <span class="hljs-keyword">if</span> (filteredCountries.length === <span class="hljs-number">0</span>) {
    noResults.style.display = <span class="hljs-string">"block"</span>;
  } <span class="hljs-keyword">else</span> {
    filteredCountries.forEach(<span class="hljs-function">(<span class="hljs-params">country</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> li = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"li"</span>);
      li.textContent = country.name;
      resultList.appendChild(li);
    });
    noResults.style.display = <span class="hljs-string">"none"</span>;
  }

  <span class="hljs-keyword">if</span> (searchInput.value === <span class="hljs-string">""</span>) {
    resultList.innerHTML = <span class="hljs-string">""</span>;
  }
};

searchInput.addEventListener(<span class="hljs-string">"input"</span>, handleSearch);
</code></pre>
<p>A) Primero listamos los posibles resultados a la bsqueda del usuario, en mi caso son pases. Para eso listamos un array de objetos en donde cada uno de esos objetos nos representa un resultado posible para el usuario con su clave y valor.</p>
<p>B) Como segundo paso capturamos los IDs que tenemos en el HTML que corresponden al (de donde vamos a capturar lo que escriba el usuario), al <code>&lt;ul/&gt;</code> (de donde vamos a mostrar la lista de resultados) y al</p>
<p>En donde mostraremos un mensaje en caso de que no se encuentren resultados.</p>
<p>C) Por ltimo armamos la funcin handleSearch en donde manejamos toda la lgica.</p>
<p>Esto lo divido en varias partes para poder explicarlo mejor paso a paso.</p>
<p>C.1) Lo primero consiste en crear dos constantes que son claves para para funcionalidad de este proyecto:</p>
<p>La Primera ellas (searchTerm) captura el valor de lo que se esta escribiendo en el input, es decir, cada letra que el usuario esta tipeando transformndolas a minscula (con toLowerCase), para asegurase de mas all de como escriba el usuario, siempre vamos a evaluar los resultados en minscula.</p>
<p>La Segunda (filteredCountries) va a ir filtrando todos los nombres del array de objetos pases pasados a minscula (para coincidir con searchTerm) y por ultimo con el mtodo startsWith que se encarga de hacer la filtracin de pases condicionando que nicamente devuelva aquellos pases del array que comiencen con las letras que esta escribiendo el usuario es decir, la constante searchTerm.</p>
<p>C.2) En esta paso con innerHTML nos aseguramos de que el la lista de pases comience en blanco.</p>
<p>C.3) En este punto tenemos un If, Else. Dentro del If nos aseguramos que si dentro el array de pases filtrados (filteredCountries) no hay pases que mostrar, es decir, que no se encontraron resultados que coincidan con la bsqueda del usuario y por por la tanto su extensin en igual 0, entonces se mostrara el <code>&lt;p&gt;</code> para avisar que no se encontraron resultados.</p>
<p>Dentro del Else colocamos el caso contrario, que seria bsicamente se encontraron resultados y que hay que mostrarlos. Para ello creamos una etiqueta <code>&lt;li&gt;</code> y dentro de ella agregamos un contenido de texto con el nombre del pas a mostrar y colamos esas <code>&lt;li&gt;</code> dentro del <code>&lt;ul&gt;</code>.</p>
<p>Por ultimo nos aseguramos que el</p>
<p>que muestra que no hay resultados quede desactivado.</p>
<p>C.4) Con este ultimo IF nos aseguramos que al ejecutarse nuestra funcionalidad, la etiqueta <code>&lt;ul&gt;</code> con pases no se muestre en caso de que el usuario no escriba nada en el <code>&lt;input&gt;</code> o este vaco.</p>
<p>C.5) En este ultimo paso hacemos el llamado a la funcin handleSearch cuando se ejecute el evento input (es decir, cuando el usuario escriba algo en el <code>&lt;input&gt;</code>)</p>
<p>Bueno, esto fue todo por este articulo, espero que te sirva para crear tu filtro de bsqueda.</p>
<p>Muchas gracias y que la pases bien. Saludos, Pablo.</p>
]]></description><link>https://onthecode.blog/creando-un-filtro-de-busqueda-con-javascript</link><guid isPermaLink="true">https://onthecode.blog/creando-un-filtro-de-busqueda-con-javascript</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[spanish]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Pablo Mchn]]></dc:creator></item><item><title><![CDATA[Como utilizar la API de Mercado Pago con Javascript en 2024]]></title><description><![CDATA[<p>Primero que nada, me gustara aclarar que este artculo no va a ser un tutorial paso a paso sobre cmo utilizar la API de Mercado Pago. Eso ya lo hice en video y aca te los dejo. Estn al da de hoy actualizados, tanto con JavaScript como con React.js</p>
<p>Pero bien, aca van los videos:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=vEXwN9-tKcs&amp;t=1742s">https://www.youtube.com/watch?v=vEXwN9-tKcs&amp;t=1742s</a></div>
<p> </p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=-VD-l5BQsuE&amp;t=3s">https://www.youtube.com/watch?v=-VD-l5BQsuE&amp;t=3s</a></div>
<p> </p>
<p>Te los recomiendo. De hecho, despus de estos, hay ms videos en mi canal sobre cmo integrar el checkout de Mercado Pago como un modal o con distintos tipos de redirecciones, as como tambin cmo capturar informacin un pago exitoso.</p>
<p>Por otro lado, me gustara elaborar una gua sobre cmo utilizar la versin anterior de esta API. Esto est destinado principalmente a ayudar a aquellas personas que hayan visto mis videos sobre esta API en mi canal de YouTube, pero aquellos que se encuentren desactualizados y estn buscando aprovechar esos proyectos sin necesidad de modificar el cdigo de mercado pago a la ltima versin como se muestra en los vdeos que compart ms arriba.</p>
<p>Dejo ac el link directo a los videos que han quedado desactualizados para que tengas a mano el tutorial que ests siguiendo.</p>
<p>Integracin Mercado Pago con Javascript: <a target="_blank" href="https://www.youtube.com/watch?v=vXqo-hgvvZU&amp;t=72s">ver video</a></p>
<p>Integracin Mercado Pago con ReactJs: <a target="_blank" href="https://www.youtube.com/watch?v=uXe_TxNVOkI&amp;t=2853s">ver video</a></p>
<p>Proyecto Donaciones Mercado Pago Javascript: <a target="_blank" href="https://www.youtube.com/watch?v=dj2oDclOJiE&amp;t=577s">ver video</a></p>
<p>Proyecto Donaciones Mercado Pago ReactJs: <a target="_blank" href="https://www.youtube.com/watch?v=WJdF5N8BiMY&amp;t=994s">ver video</a></p>
<p>Ecommerse principiantes Mercado Pago Javascript: <a target="_blank" href="https://www.youtube.com/watch?v=pZaJNCXO89Y&amp;t=4187s">ver video</a></p>
<h2 id="heading-solucionando-conflictos-de-version-de-mercado-pago">Solucionando conflictos de versin de Mercado Pago</h2>
<p>Lo que se debe hacer es asegurarse de tener alguna versin compatible de mercado pago en lugar de tener la ultima versin que se te instale por defecto. Nada mas que eso, el resto del cdigo queda tal cual.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749462613538/131a16bd-b81e-4cd1-b013-47adfef86d40.png" alt="Archivo package.json" /></p>
<p>Como vern por defecto se nos instala la ultima versin de mercado pago, puede que sea la misma que ves en la imagen o incluso alguna superior.</p>
<p>Esto hace que al correr el servidor nos de seguramente este error:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749462614585/f4e8fce0-94f7-4823-8821-279273ca2514.png" alt="Error en terminal" /></p>
<p>Esto es por que las ultimas versiones de mercado pago no resisten configure como manera optima para vincular las credenciales de nuestra cuenta.</p>
<p>Entonces <strong>hay que modificar la lnea del archivo package.json y colocar una versin de Mercado Pago adecuada</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749462615711/2d94ac70-1625-44c0-8f1e-7f8e13203541.png" alt="Archivo package.json" /></p>
<p>Cololoca en tu archivo package.json la version "^1.5.17" de Mercado Pago.</p>
<p>Ahora hay que <strong>eliminar la capeta node modules y el archivo package-lock.json</strong> de tu cdigo. Una ves hecho esto hay que volver a instalar las dependencias del proyecto, en nuestro caso mercadopago cors y express.</p>
<p>Corre el siguiente comando en la consola:</p>
<p><code>npm install mercadopago cors express</code></p>
<p>Perfecto esto es todo!</p>
<p>Ya podes seguir el tutorial y el codigo te va a funcionar perfecto</p>
<p>Saludos!</p>
]]></description><link>https://onthecode.blog/como-utilizar-la-api-de-mercado-pago-con-javascript-en-2024</link><guid isPermaLink="true">https://onthecode.blog/como-utilizar-la-api-de-mercado-pago-con-javascript-en-2024</guid><dc:creator><![CDATA[Pablo Mchn]]></dc:creator></item><item><title><![CDATA[Botones de scroll horizontal con html - css y Javascript]]></title><description><![CDATA[<p>Vamos a programar en este articulo dos botones para hacer scroll horizontal con html, css y unas pocas lneas de JavaScript.</p>
<p>Vas a poder encontrar el cdigo explicado paso a paso y te va a quedar disponible para que lo puedas copiar y probar en tu propio proyecto.</p>
<p>Antes de arrancar te dejo tambin disponible este tutorial en vdeo.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/K9gOZZFcHoY?si=kxvozNVl6lwTlkX9">https://youtu.be/K9gOZZFcHoY?si=kxvozNVl6lwTlkX9</a></div>
<p> </p>
<p>No olvides suscribirte a mi canal, subo contenido regularmente! ahora si , comenzamos con el cdigo.</p>
<h2 id="heading-1-comenzamos-creando-la-maquetacion-html">1 - Comenzamos creando la maquetacin HTML.</h2>
<pre><code class="lang-javascript">&lt;!DOCTYPE html&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"styles.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Document<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-buttons-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"scrolling-button-left"</span>&gt;</span>👈<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"scrolling-button-right"</span>&gt;</span>👉<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scrolling-card"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Soy una card Feliz<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"app.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></span>
</code></pre>
<p>A - Primero, dentro de un contenedor tenemos nuestros dos botones, en mi caso son unas etiquetas span que me simulan un botn y que dentro contienen un emoji. En tu caso, podras utilizar botones o lo que se ajuste a tu proyecto, lo importante es que les pongas un ID para poder identificarlo.</p>
<p>B - Por ultimo, dentro de un segundo contenedor, ponemos todas nuestras cards, cada una de ellas debe compartir una clase css.</p>
<h2 id="heading-2-aplicamos-los-estilos-css">2 - Aplicamos los estilos CSS.</h2>
<pre><code class="lang-javascript">.scrolling-container {
  <span class="hljs-attr">display</span>: flex;
  flex-wrap: nowrap;
  overflow-x: auto;
  scroll-behavior: smooth;
}

.scrolling-card {
  <span class="hljs-attr">flex</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> auto;
  border: solid <span class="hljs-number">1</span>px black;
  margin: <span class="hljs-number">10</span>px;
  width: <span class="hljs-number">250</span>px;
  height: <span class="hljs-number">150</span>px;
  text-align: center;
}

.scrolling-container::-webkit-scrollbar {
  <span class="hljs-attr">display</span>: none;
}

.scrolling-buttons-container {
  <span class="hljs-attr">display</span>: flex;
  justify-content: space-between;
  font-size: <span class="hljs-number">25</span>px;
  margin-left: <span class="hljs-number">25</span>px;
  margin-right: <span class="hljs-number">25</span>px;
}
</code></pre>
<p>A - Scrolling-container: Es el primer contenedor en el que se ordena la distribucin de todas las cards a las cuales les vamos a dar la posibilidad de desplazarse de izquierda a derecha.</p>
<p>Utilizamos flexbox para lograr mostrar todas las cards en una misma fila. Adems, le pasamos un comportamiento de scroll tipo smooth para generar mas suavidad en el desplazamiento de las cards.</p>
<p>B - Scrolling-card: Esta clase corresponde a cada card en particular, a las cuales alineamos con flexbox y les damos un estilo de aspecto y posicionamiento dentro de la web.</p>
<p>C - Scrolling-container::-webkit-scrollbar: En esta parte simplemente le decimos a la clase scrolling-container que queremos que nos elimine la barra de scroll horizontal que se muestra por defecto. Esta barra no se ve agradable en el diseo y la funcionalidad de desplazamiento la tendrn los botones.</p>
<p>D - Scrolling-buttons-container: Esta clase corresponde al contenedor de los botones en donde les damos un tamao y un posicionamiento en la web.</p>
<h2 id="heading-3-funcionalidad-de-los-botones-con-javascript">3 - Funcionalidad de los botones con JavasCript.</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> rightBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#scrolling-button-right"</span>);
<span class="hljs-keyword">const</span> leftBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#scrolling-button-left"</span>);

<span class="hljs-keyword">const</span> content = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".scrolling-container"</span>);

rightBtn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> {
  content.scrollLeft += <span class="hljs-number">800</span>;
});

leftBtn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> {
  content.scrollLeft -= <span class="hljs-number">800</span>;
});
</code></pre>
<p>A) Primero atrapamos el ID de ambos botones y la clase contenedora de todas las cards guardando esos valores dentro de unas constantes. Una vez hecho esto, ya estamos en condiciones de armar la funcionalidad.</p>
<p>B) Llega el momento de utilizar la propiedad scrollLeft para lograr la funcionalidad de desplazar a la derecha o a la izquierda el contenido. Se que es confuso, pero no hay una propiedad que se llame scrollRight. Simplemente con scrollLeft vamos a poder mover el contenido para ambos lados de las siguiente manera:</p>
<p>Para mover el contenido a la derecha le pasamos el escuchador de eventos al botn indicado y le pedimos que mueva el content (el contenedor de cards) hacia la derecha los pixeles que queramos utilizando scrollLeft con (+=) Es importante resaltar el +.</p>
<p>Para mover el contenido a la izquierda utilizamos exactamente la misma lgica pero esta vez utilizando el scrollLeft con signo (-=) Utilizamos el negativo para desplazar el contenido en sentido opuesto.</p>
<p>Eso es todo lo necesario para lograr el comportamiento de scroll horizontal utilizado botones.</p>
<p>Espero que te sirva y que la pases muy bien!</p>
<p>Saludos, Pablo.</p>
]]></description><link>https://onthecode.blog/botones-de-scroll-horizontal-con-html-css-y-javascript</link><guid isPermaLink="true">https://onthecode.blog/botones-de-scroll-horizontal-con-html-css-y-javascript</guid><category><![CDATA[spanish]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Pablo Mchn]]></dc:creator></item><item><title><![CDATA[Solucionando conflictos de CORS al acceder a la API del Banco Central de Argentina]]></title><description><![CDATA[<p>Si ests intentando utilizar la API del Banco Central de Argentina desde el front-end de tu sitio web, es posible que te encuentres con un problema de seguridad conocido como CORS. En pocas palabras, CORS es una medida de seguridad implementada por los navegadores web para evitar que una pgina web haga solicitudes a un servidor desde un dominio diferente al que el servidor est configurado para permitir.</p>
<p>Hace un tiempo hice un video de YouTube en mi canal <a target="_blank" href="http://www.youtube.com/@onthecode">on the code</a> sobre cmo consumir la API del BCRA con Javascript, pero al recibir consultas sobre cmo resolver el problema de CORS sin utilizar una extensin del navegador (que era lo que estaba haciendo en mi vdeo), decid crear un proxy para solucionar este problema.</p>
<p>Primero te dejo el video, no olvides suscribirte a mi canal! subo contenido periodicamente.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/_Wl-CiBlIds?si=f1mYKupGopJgzczX">https://youtu.be/_Wl-CiBlIds?si=f1mYKupGopJgzczX</a></div>
<p> </p>
<p>Antes de seguir no te olvides de suscribirte a mi canal, subo contenido regularmente.</p>
<p>Todo esto de CORS es muy comn en las aplicaciones web modernas, ya que a menudo utilizan mltiples servidores y dominios diferentes. Afortunadamente, existe una solucin simple para este problema: usar un proxy.</p>
<p>Un proxy es bsicamente un servidor que acta como intermediario entre tu aplicacin y el servidor que ests intentando acceder. En otras palabras, en lugar de hacer una solicitud directa al servidor, haces la solicitud al proxy, y el proxy hace la solicitud al servidor en tu nombre. Esto permite que la solicitud provenga del mismo dominio que tu aplicacin, evitando conflictos con CORS.</p>
<p>En mi caso, quera acceder a la API del Banco Central de Argentina desde mi sitio web, por lo que cre un proxy para solucionar el problema de CORS. No dudes en utilizar el proxy! ac te comento como hacerlo:</p>
<p>Te muestro un ejemplo para acceder a la cotizacin del USD, aunque con el proxy se puede acceder a cualquier informacin que ofrezca la api del BCRA.</p>
<p>Ac te dejo el link a la API: <a target="_blank" href="https://estadisticasbcra.com/api/documentacion">https://estadisticasbcra.com/api/documentacion</a></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> apiUrl = <span class="hljs-string">"usd"</span>;
<span class="hljs-keyword">const</span> proxyUrl = <span class="hljs-string">"https://bcra-proxy-cors.vercel.app"</span>;

fetch(<span class="hljs-string">`<span class="hljs-subst">${proxyUrl}</span>/<span class="hljs-subst">${apiUrl}</span>`</span>, {
  <span class="hljs-attr">headers</span>: {
    <span class="hljs-attr">Authorization</span>:
      <span class="hljs-string">"BEARER TOKEN"</span>,
  },
})
  .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
  .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(data))
</code></pre>
<p>Este cdigo utiliza fetch para hacer una solicitud GET a la API del Banco Central de Argentina.</p>
<ol>
<li><p>En la primera const apiUrl, especificamos la informacin a la que nos gustara acceder. No es necesario escribir la URL completa de la solicitud, de eso se encarga el Proxy. Por lo tanto, solo se debe escribir exactamente lo que se desea acceder (en este caso "usd").</p>
</li>
<li><p>En la segunda const proxyUrl, especificamos la URL del proxy. Desplegu el proxy en Vercel, ya que siempre me ha dado muy buenos resultados y es gratuito.</p>
</li>
<li><p>En los headers de la peticin, debemos especificar el token BEARER como una cadena de caracteres. Este token se obtiene al registrarse en la API.</p>
</li>
</ol>
<p>Mejor sera hacer lo mismo con async-await try-catch ;)</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
   <span class="hljs-keyword">const</span> apiUrl = <span class="hljs-string">"usd"</span>;
   <span class="hljs-keyword">const</span> proxyUrl = <span class="hljs-string">"https://bcra-proxy-cors.vercel.app"</span>;

   <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`<span class="hljs-subst">${proxyUrl}</span>/<span class="hljs-subst">${apiUrl}</span>`</span>, {
      <span class="hljs-attr">headers</span>: {
              <span class="hljs-attr">Authorization</span>:
              <span class="hljs-string">"BEARER TOKEN"</span>,
            },
          });

      <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
        <span class="hljs-built_in">console</span>.log(data);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(error);
        }
      };

      fetchData();
</code></pre>
<p>Eso es todo lo que necesitas hacer para utilizar el proxy y evitar todo conflicto con CORS. Que la pasen bien!</p>
<p>Saludos!!</p>
<p>Pablo.</p>
]]></description><link>https://onthecode.blog/solucionando-conflictos-de-cors-al-acceder-a-la-api-del-banco-central-de-argentina</link><guid isPermaLink="true">https://onthecode.blog/solucionando-conflictos-de-cors-al-acceder-a-la-api-del-banco-central-de-argentina</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[spanish]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Pablo Mchn]]></dc:creator></item><item><title><![CDATA[Como deployar proyecto Backend con Node.js y Expess.js en Vercel]]></title><description><![CDATA[<p>Se hace bastante simple deployar un proyecto backend con NodeJS y Express en vercel, solo hay que tener en cuenta algunas pocas cosas! te lo voy a ir mostrando en este articulo paso paso, dejndote tambin el cdigo de ejemplo para que te lo puedas copiar y probar en tu proyecto.</p>
<p>Te dejo tambin el paso a paso en video, no te olvides de suscribirte a mi canal .</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=h3NVEN2iy6k">https://www.youtube.com/watch?v=h3NVEN2iy6k</a></div>
<p> </p>
<h2 id="heading-preparando-proyecto-para-deployar-en-vercel">Preparando proyecto para deployar en Vercel</h2>
<p>Vamos a comenzar creando un proyecto simple para deployar, en tu editor de cdigo crea una carpeta llamada app. Dentro de esta carpeta corre el siguiente comando en la consola:</p>
<p><code>npm init -y</code></p>
<p>Esto va a crear un archivo package.json con informacin bsica y necesaria del proyecto.</p>
<p>Ahora, dentro de nuestra carpeta app hay que crear otro archivo al cual lo vamos a llamar index.js, es importantsimo que se llame index.js y no de otra forma como app.js o server.js, vercel va a buscar un archivo que se llame index.js a la hora de deployar el cdigo.</p>
<p>Entonces la estructura tiene que ir quedando algo mas o menos como esto:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749462172859/8e251d28-aceb-4a96-bd7e-3f23100685c5.png" alt="Proyecto deploy backend en vercel estructura de carpetas" class="image--center mx-auto" /></p>
<p>Bueno, comencemos a escribir un poco de cdigo en nuestro index.js. Te dejo ac un cdigo bsico para que te sirva como referencia.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> app = express();

<span class="hljs-keyword">const</span> port = process.env.PORT || <span class="hljs-number">3000</span>;

app.get(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> htmlResponse = <span class="hljs-string">`
    &lt;html&gt;
      &lt;head&gt;
        &lt;title&gt;NodeJs y Express en Vercel&lt;/title&gt;
      &lt;/head&gt;
      &lt;body&gt;
        &lt;h1&gt;Soy un proyecto Back end en vercel&lt;/h1&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  `</span>;
  res.send(htmlResponse);
});

app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`port runing in http://localhost:<span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<p>A este punto seguramente tengas un proyecto propio o tengas en mente deployar otra cosa, pero paso a dar una explicacin rpida del cdigo que esta ac arriba, quizs te sirva.</p>
<ol>
<li>Lo primero que esta haciendo es requerir a Express y luego invocarlo en la constante app</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> app = express();
</code></pre>
<p>Al estar utilizando Express tenemos que instalarlo para que funcione 😅 Ejecuta este comando en la consola, siempre dentro de la carpeta app</p>
<p><code>npm i express</code></p>
<ol start="2">
<li>Lo segundo (y super importante) es la configurcion del puerto en la constante port.</li>
</ol>
<p><code>const port = process.env.PORT || 3000;</code></p>
<p>En este punto el estamos diciendo que nuestro proyecto va a correr en un determinado dominio o en nuestro caso en alguna url que nos genere vercel. Eso lo indicamos con el (process.env.PORT). Luego le decimos que en caso de no haber ningn dominio/url configurada lo vamos a levantar en nuestro servidor local en el puerto 3000, con esto: ( || 3000). Pero todo bien! seguro que se nos va a configurar una url en vercel!</p>
<ol start="3">
<li>Vamos con lo tercero, pero en verdad lo importante ya se hizo en el paso 2. Lo dems ya va a estar ajustado a lo que suceda en tu proyecto. En mi caso solo tengo configurado un poco de cdigo HTML para mostrar en el navegador cuando se ejecute el servidor.</li>
</ol>
<pre><code class="lang-javascript">app.get(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> htmlResponse = <span class="hljs-string">`
    &lt;html&gt;
      &lt;head&gt;
        &lt;title&gt;NodeJs y Express en Vercel&lt;/title&gt;
      &lt;/head&gt;
      &lt;body&gt;
        &lt;h1&gt;Soy un proyecto Back end en vercel&lt;/h1&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  `</span>;
  res.send(htmlResponse);
});
</code></pre>
<ol start="4">
<li>Por ultimo, le pedimos a la constante app (donde esta corriendo express) que escuche el puerto que configuramos mas arriba y que nos de un poco de feedback por consola.</li>
</ol>
<pre><code class="lang-javascript">app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`port runing in http://localhost:<span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<p>Bueno, ahora ya estamos en condiciones de probar el proyecto en nuestro servidor local (se va a levantar en el puerto 3000) para ver si todo esta funcionando, hay que correr este comando en la consola.</p>
<p><code>node index.js</code></p>
<p>Funcion? Bueno, si esta todo bien, sea no te dio ningn error y tu proyecto se ejecuto bien en el puerto 3000 de tu servidor local, entonces ya estamos en condiciones de subirlo a vercel.</p>
<h2 id="heading-preparando-configuraciones-del-proyecto-para-deployar-en-vercel">Preparando configuraciones del proyecto para deployar en vercel</h2>
<p>Lo primero que tenemos que hacer a esta altura es crear un archivo de extensin json llamado vercel.json (de nuevo, siempre dentro de la carpeta app), dentro de este archivo van las configuraciones bsicas que necesita vercel, ac te lo muestro:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"builds"</span>: [
    {
      <span class="hljs-attr">"src"</span>: <span class="hljs-string">"./index.js"</span>,
      <span class="hljs-attr">"use"</span>: <span class="hljs-string">"@vercel/node"</span>
    }
  ],
  <span class="hljs-attr">"routes"</span>: [
    {
      <span class="hljs-attr">"src"</span>: <span class="hljs-string">"/(.*)"</span>,
      <span class="hljs-attr">"dest"</span>: <span class="hljs-string">"/"</span>
    }
  ]
}
</code></pre>
<p>No me quiero meter demasiado en esto, pero son las configuraciones necesarias en los "builds" y las "routes" que necesitamos para hacer funcionar el deploy.</p>
<p>Algo sinttico seria lo siguiente:</p>
<p>Builds: Definen como se construye la aplicacin, en este punto usamos nuestro archivo index.js empleado dentro del entorno de ejecucin @vercel/node.</p>
<p>Routes: Define como se manejan las rutas de la aplicacin. Todas las URl representadas como /(.*) Se van a redirigir a la raiz del sitio (/).</p>
<p>Mientras tanto la estructura de tu proyecto se debera ver como algo as (o eso espero).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749462173849/01ccf443-b0ee-4f0c-969b-d285fc1b7f87.png" alt="Proyecto deploy backend en vercel estructura de carpetas" class="image--center mx-auto" /></p>
<h2 id="heading-deployando-el-proyecto-en-vercel">Deployando el proyecto en vercel</h2>
<p>Bueno, ahora vamos con lo ultimo, llego al fin el momento de subir esto a vercel. Primero hay que crear una cuenta si es que aun no te hiciste una, crear una cuenta en vercel es totalmente gratis y no te pide ninguna tarjeta de crdito ni nada de eso, crea una cuenta aca: https://vercel.com</p>
<p>Hay dos maneras de hacer el deploy, una es vinculando un repositorio y otra es utilizando el CLI de vercel y hacerlo todo por consola, yo prefiero usar la consola, es muy simple y ademas no hay necesidad de subir todo a github, te cuento como hacerlo.</p>
<p>Si nunca antes instalaste vercel llego el momento de hacerlo! En tu consola corre el siguiente comando para instalar vercel de forma global.</p>
<p><code>npm install -g vercel</code></p>
<p>Ahora si! ya podemos usar el CLI y subir el proyecto por consola.</p>
<p>Hay que correr simplemente el comando vercel.</p>
<p><code>vercel</code></p>
<p>Una ves que corras ese comando se te van a mostrar algunas pocas preguntas en tu consola que hay que contestar.</p>
<p>Te las muestro por ac y te las explico:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749462174693/b472490e-d645-4617-87c4-a0339fbe3451.png" alt="Visualizacion del cuestionario de vercel al deployar" class="image--center mx-auto" /></p>
<p>Set up and deploy: Ac le ponemos que si con la letra: y</p>
<p>Wich scope do you want to deploy to? Ac nos pregunta en que mbito deseamos desplegar el proyecto. A mi me aparece pab-mchn porque es el nombre de mi cuenta y estoy logeado. Si aun no te logeaste, te va a pedir que te logees, es un proceso simple y se gestiona con una confirmacin de cuenta con el navegador.</p>
<p>Link to existing project? Ac nos pregunta si lo queremos vincular a un proyecto que se tenga creado en Vercel, le ponemos que no con una simple n. A no ser que si lo quieras vincular a un proyecto que tengas creado.</p>
<p>Whats is your project`s name? Ac todo bien, simplemente nos pregunta el nombre que le queramos poner a nuestro proyecto. Creale alguno o busca cual es el nombre de tu proyecto si es que en la anterior respuesta pusiste que si.</p>
<p>In wich directory is your code located? Ac nos pregunta donde esta ubicado nuestro proyecto y nos sugiere esta respuesta ./ Esta respuesta es correcta, nuestro archivo index.js esta en la raz del proyecto dentro de la carpeta app as que la ubicacin es correcta, simplemente damos un "Enter".</p>
<p>Y listo! Vercel va a generar los links para deployar el proyecto y ya vamos a poder verlo en las URL que nos esta mostrando en la consola. mralas en tu navegador.</p>
<p>En caso de que quieras subirlo a produccin deberas correr este comando (ya te lo sugiere por ah en consola ).</p>
<p><code>vercel --prod</code></p>
<p>Bueno, eso es todo!</p>
<p>Espero que puedas tener tu hermoso proyecto en vercel y que la pases bien.</p>
<p>Saludos! Pablo.</p>
]]></description><link>https://onthecode.blog/como-deployar-proyecto-backend-con-nodejs-y-expessjs-en-vercel</link><guid isPermaLink="true">https://onthecode.blog/como-deployar-proyecto-backend-con-nodejs-y-expessjs-en-vercel</guid><category><![CDATA[Web Development]]></category><category><![CDATA[spanish]]></category><category><![CDATA[Vercel]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Pablo Mchn]]></dc:creator></item><item><title><![CDATA[Buscador y filtrado de productos en Javascript]]></title><description><![CDATA[<p>Vamos a crear en este articulo un buscador y filtrado de productos en JavaScript paso a paso.</p>
<p>Te voy a ir dejando el cdigo limpio para que puedas copiarlo y probarlo en tu proyecto junto con explicaciones.</p>
<p>Te dejo tambin el video de este tutorial por si te interesa tenerlo a mano.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/8yBQnHhM12o?si=WtHyPGL8SeEmWhC6">https://youtu.be/8yBQnHhM12o?si=WtHyPGL8SeEmWhC6</a></div>
<p> </p>
<h2 id="heading-1-el-html-del-buscador-del-productos-en-javascript">1) El HTML del buscador del productos en javaScript</h2>
<pre><code class="lang-javascript">&lt;!DOCTYPE html&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"styles.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Document<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>BUSCAR PRODUCTOS<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- search content --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"search-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"searchInput"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search products..."</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"noResults"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"no-results"</span>&gt;</span>No se encontraron resultados.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- shop content --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-products-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"shopContent"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"app.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></span>
</code></pre>
<p>En este HTML se encuentra nicamente un <code>&lt;input&gt;</code> en donde el usuario va a escribir el producto que desea buscar junto con una etiqueta <code>&lt;p&gt;</code>, la cual contendr un texto que se va a mostrar nicamente en caso de que no se encuentren resultados para mostrar.</p>
<p>Por ultimo, se encuentra un <code>&lt;div&gt;</code> que ser el contenedor de los productos.</p>
<p>Cada una de estas etiquetas tienen clases y ids que son necesarios tanto para estilos como para la funcionalidad y dinamismo que se les dar en un futuro con JavaScript.</p>
<h2 id="heading-2-estilos-de-la-barra-de-busqueda-y-de-los-productos">2) Estilos de la barra de bsqueda y de los productos</h2>
<pre><code class="lang-javascript">h1 {
  text-align: center;
}
.search-container {
  max-width: <span class="hljs-number">400</span>px;
  margin: <span class="hljs-number">0</span>vh auto;
  padding: <span class="hljs-number">20</span>px;
}

input[type=<span class="hljs-string">"text"</span>] {
  <span class="hljs-attr">width</span>: <span class="hljs-number">100</span>%;
  padding: <span class="hljs-number">10</span>px;
  font-size: <span class="hljs-number">16</span>px;
  border: <span class="hljs-number">1</span>px solid #<span class="hljs-number">646363</span>;
  border-radius: <span class="hljs-number">8</span>px;
  outline: none;
}
.card-products-container {
  <span class="hljs-attr">margin</span>: <span class="hljs-number">10</span>vh auto;
  text-align: center;
}

.card-products {
  <span class="hljs-attr">display</span>: inline-block;
  text-align: center;
  margin: <span class="hljs-number">0</span> <span class="hljs-number">30</span>px;
}

.card-products img {
  <span class="hljs-attr">height</span>: <span class="hljs-number">180</span>px;
}

.card-products h3,
.card-products .price {
  margin-top: <span class="hljs-number">10</span>px;
}

.card-products button {
  <span class="hljs-attr">border</span>: none;
  outline: <span class="hljs-number">0</span>;
  padding: <span class="hljs-number">10</span>px;
  color: white;
  background-color: #<span class="hljs-number">1</span>bcb7f;
  text-align: center;
  cursor: pointer;
  width: <span class="hljs-number">80</span>%;
  font-size: <span class="hljs-number">15</span>px;
}

.no-results {
  font-size: <span class="hljs-number">20</span>px;
  color: red;
  text-align: center;
  display: none;
}
</code></pre>
<p>Te dejo los estilos, efectivamente solo hacen a la esttica del proyecto. Lo nico a tener en cuenta en relacin a la funcionalidad es el "display:none" que se encuentra en la clase ".no-results", esto vendra a ser que el prrafo no se muestre por default en la pagina web. El dinamismo de mostrarse cundo sea necesario se lo vamos a dar en el JavaScript.</p>
<h2 id="heading-3-codigo-javascript-para-ver-filtrar-y-buscar-productos">3) Cdigo JavaScript para ver, filtrar y buscar productos</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> products = [
  {
    <span class="hljs-attr">productName</span>: <span class="hljs-string">"Sandia"</span>,
    <span class="hljs-attr">price</span>: <span class="hljs-number">15</span>,
    <span class="hljs-attr">img</span>: <span class="hljs-string">"https://res.cloudinary.com/pabcode/image/upload/v1699869750/e-commerce/ksmw5s3xg7eeakpva5xd.png"</span>,
  },
  {
    <span class="hljs-attr">productName</span>: <span class="hljs-string">"Cervecita"</span>,
    <span class="hljs-attr">price</span>: <span class="hljs-number">20</span>,
    <span class="hljs-attr">img</span>: <span class="hljs-string">"https://res.cloudinary.com/pabcode/image/upload/v1699869747/e-commerce/xhlekqrockwxzjskzppw.png"</span>,
  },
  {
    <span class="hljs-attr">productName</span>: <span class="hljs-string">"Bananita"</span>,
    <span class="hljs-attr">price</span>: <span class="hljs-number">30</span>,
    <span class="hljs-attr">img</span>: <span class="hljs-string">"https://res.cloudinary.com/pabcode/image/upload/v1699871193/e-commerce/mopgcvdiepr8axkazmcp.png"</span>,
  },
  {
    <span class="hljs-attr">productName</span>: <span class="hljs-string">"Compu"</span>,
    <span class="hljs-attr">price</span>: <span class="hljs-number">40</span>,
    <span class="hljs-attr">img</span>: <span class="hljs-string">"https://res.cloudinary.com/pabcode/image/upload/v1700045911/e-commerce/compu_unvcoi.png"</span>,
  },
];
<span class="hljs-keyword">const</span> shopContent = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"shopContent"</span>);
<span class="hljs-keyword">const</span> searchInput = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"searchInput"</span>);
<span class="hljs-keyword">const</span> noResults = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"noResults"</span>);

<span class="hljs-keyword">const</span> displayProducts = <span class="hljs-function">(<span class="hljs-params">productList</span>) =&gt;</span> {
  shopContent.innerHTML = <span class="hljs-string">""</span>;

  <span class="hljs-keyword">if</span> (productList.length === <span class="hljs-number">0</span>) {
    noResults.style.display = <span class="hljs-string">"block"</span>;
  } <span class="hljs-keyword">else</span> {
    productList.forEach(<span class="hljs-function">(<span class="hljs-params">product</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> content = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
      content.className = <span class="hljs-string">"card-products"</span>;
      content.innerHTML = <span class="hljs-string">`
          &lt;img src="<span class="hljs-subst">${product.img}</span>"&gt;
          &lt;h3&gt;<span class="hljs-subst">${product.productName}</span>&lt;/h3&gt;
          &lt;p class="price"&gt;<span class="hljs-subst">${product.price}</span>&lt;/p&gt;
          &lt;button&gt;comprar&lt;/button&gt;
          `</span>;
      shopContent.append(content);
    });
    noResults.style.display = <span class="hljs-string">"none"</span>;
  }
};

<span class="hljs-keyword">const</span> handleSearch = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> searchTerm = searchInput.value.toLowerCase();
  <span class="hljs-keyword">const</span> filteredProducts = products.filter(<span class="hljs-function">(<span class="hljs-params">product</span>) =&gt;</span> product.productName.toLowerCase().startsWith(searchTerm));

  displayProducts(filteredProducts);
};

displayProducts(products);

searchInput.addEventListener(<span class="hljs-string">"input"</span>, handleSearch);
</code></pre>
<p>Por ultimo tenemos el JavaScript, vayamos viendo paso a paso que es lo que hace.</p>
<ol>
<li><p>Lo primero es tener listados nuestros productos, en mi caso tengo un array de objetos, cada producto tienen un nombre, precio e imagen.</p>
</li>
<li><p>Lo siguiente es capturar mediante sus id las etiquetas que estn en HTML y que necesitamos para lograr el dinamismo y la funcionalidad.</p>
</li>
<li><p>Es momento de comenzar a armar la funcin que va a desplegar los productos, en este caso se llama displayProducts().Vamos viendo paso a paso que es lo que hace esta funcin.</p>
</li>
</ol>
<p>a) Lo primero es notar que la funcin tiene como parmetro productList. Este parmetro representa dos cosas distintas segn lo que le pasamos al momento de invocar la funcin. Puede ser el array de productos en si mismo o puede ser tambin los productos que han sido filtrados y que debemos mostrarle a usuario como resultados de su bsqueda.</p>
<p>b) Como primera linea dentro de la funcin nos aseguramos que el shopContent este limpio cada vez que se ejecute la funcin. Esto lo hacemos para asegurarnos que los productos no aparezcan duplicados mientras vamos ejecutando la funcionalidad de nuestro programa.</p>
<p>c) Lo siguiente es un if(), else(). Dentro del if() tenemos nicamente un "display:block" al prrafo que muestra que no se encontraron resultados en caso de que se cumpla la condicin tener al producList con una extensin de 0.</p>
<p>Dentro del else() simplemente recorremos los productos filtrados con un forEach y armamos las cards con lo productos para mostrar en el sitio web, adems anulamos con un "display:none" el prrafo que muestra que no hay resultados para asegurarnos de que no se muestre.</p>
<ol start="4">
<li>Es ahora el turno de la segunda funcin del proyecto handleSeach(), esta funcion es la que hace todo el proceso de filtrado y busqueda, veamos que es lo que hace.</li>
</ol>
<p>a) En la primer variable SearchTerm capturamos las letras que escribe el usuario en el input y las transformamos a minscula, esto ltimo para asegurarnos de que mas all de como escriba el usuario en el input siempre vamos a procesar toda la lgica con las letras en minscula para que no se nos generen conflictos.</p>
<p>b) La segunda variable filteredProducts lo que hace es filtrar todos los nombres del array "products" pasados a minscula (para coincidir con searchTerm). Luego con el mtodo startsWith se asegura que nicamente devuelva aquellos productos del array que comiencen con las letras que esta escribiendo el usuario, es decir, la constante searchTerm.</p>
<p>Esta ultima variable es fundamental, ya que contiene dentro de si todos los productos filtrados.</p>
<p>c) Lo siguiente es llamar a la primer funcin que creamos en este proyecto pasndole por parmetro los pases filtrados, es decir la variable filteredProducts.</p>
<ol start="5">
<li><p>Luego tenemos simplemente la invocacin del la funcin displayproducts() para mostrar los productos inicialmente al cargar la pagina.</p>
</li>
<li><p>Lo ultimo es simplemente ejecutar la funcin handleSearch() cuando se ejecute el evento input, es decir, cuando el usuario comience a tipear para buscar algn producto en la barra de bsqueda.</p>
</li>
</ol>
<p>Perfecto, espero que te sirva! Esto es todo para lograr el buscador de productos con JavaScript</p>
<p>Saludos, Pablo.</p>
]]></description><link>https://onthecode.blog/buscador-y-filtrado-de-productos-en-javascript</link><guid isPermaLink="true">https://onthecode.blog/buscador-y-filtrado-de-productos-en-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[spanish]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Pablo Mchn]]></dc:creator></item></channel></rss>