Crear una vista efectiva y atractiva para los productos en una tienda en línea es una tarea que involucra conocimientos de programación, diseño de interfaces y una adecuada gestión de los datos. En esta guía, vamos a emplear TypeScript para mejorar la presentación de un producto y asegurarnos de que la información sea mostrada de manera coherente y estructurada. También aprenderemos a manejar datos de forma dinámica con servicios que interactúan con una API, en este caso, la de Shopify. Empecemos por entender cómo implementar la vista de un producto en nuestra aplicación.
¿Cómo mejorar la visualización de un producto en la página?
Para darle un aspecto más profesional a la vista de nuestro producto, utilizaremos un componente presentacional llamado ProductView. Este componente tendrá una estructura que incluye varios elementos esenciales como la imagen, el título, las etiquetas, la descripción, el precio y la cantidad del producto.
Para integrar ProductView en nuestra página de productos, reemplazaremos el retorno actual en el manejador con este nuevo componente. Es importante tener en cuenta que TypeScript nos ayudará a garantizar que pasamos todos los datos necesarios a ProductView mediante el uso de tipos, especificamente, ProductType.
¿Qué es la estructura ProductType y por qué es importante?
ProductType es un tipo que define las propiedades esperadas de un producto, asegurando así que la información necesaria está presente y es del tipo correcto. Este tipo incluye:
ID
Título
Descripción
Precio
Imagen
Cantidad
Handle
Etiquetas
Al obtener datos de nuestra API que no coinciden con esta estructura, necesitamos transformarlos adecuadamente.
¿Cómo transformar los datos de un producto para que coincidan con nuestra estructura de datos?
Para realizar esta transformación, primero tenemos que obtener el producto por su ID a través de un servicio dedicado. A continuación, mapeamos los datos que recibimos de la API a nuestro ProductType utilizando una función de transformación en nuestro servicio. Esto nos asegura que todos los componentes que dependen de estos datos reciban lo que esperan.
Hagamos un ejemplo con el mapeo de la ID del producto:
product.variants[0].admin_graphql_api_id
Dado que las variantes vienen en un arreglo, asumimos para nuestro ejemplo que solo hay una variante por producto.
¿Cómo se obtiene un producto específico mediante su ID?
Para buscar un producto por su ID, mejoraremos el servicio de obtención de productos para que pueda aceptar un ID opcional y devuelva el producto correspondiente en el formato ProductType. En este servicio, manejamos adecuadamente los errores y aseguramos que la estructura de datos transformada sea la que se retorna.
Aquí te dejo un pequeño pseudocódigo sobre cómo se haría esa petición en nuestro servicio:
¿Cómo implementamos el servicio de productos en nuestra página?
Una vez que tengamos nuestro servicio listo y funcionando, podremos importarlo en nuestra página de productos y solicitar la información del producto utilizando el ID que obtenemos desde los parámetros de búsqueda (searchParams). Con esto, pedimos al servicio que nos devuelva el producto correcto, y pasamos estos datos al componente ProductView.
Por último, con nuestra página ya capaz de mostrar la información correcta, podemos estar seguros de que los visitantes tendrán una percepción más clara y detallada del producto que están considerando, proporcionando una experiencia de usuario más satisfactoria.
Seguir aprendiendo sobre cómo implementar y mejorar las estructuras de datos y la interacción con APIs no solo es fundamental para el desarrollo web moderno, sino que también es una aventura continua en la resolución de problemas y la innovación. ¡Adelante con tu proyecto y que cada paso te acerque a una tienda en línea impresionante!
Amo que ya esten hechos los componentes y el curso se enfoque en NEXT en lugar de explicar paso a paso el css y el html. 💚
Completamente de acuerdo, no se porque otros se quejan de esto, el hecho de que los componentes ya esten hechos da mas tiempo para que se profundice en lo que realmente nos interesa que es Next
no seria mas limpio crear un getProduct ? para no incrementar la logica en getProducts
En efecto compañero creo que del modo en que el profesor implemento la funcionalidad rompe el principio SRP de los principios SOLID al cargar dos responsabilidades en una sola función
Si les sale error del icono en ProductViewItemsOrder, solamente es instalar el paquete de iconos npm install react-icons --save
ahora, para que modificar el metodo de getProducts? en teoria esto deberia traernos todos los productos, no seria mas limpio crear un nuevo metodo que me traiga solo un producto segun el id? algo como getProduct? pregunto mas que nada para conocer bien la arquitectura de nextjs.
pregunta quizas innecesaria:
1.- cual es el standar para escribir los directorios que son asociados a una vista? con Mayuscula o minuscula?
veo que tienes el directorio de Store con mayusculas y el directorio de products con minusculas, cual seria el correcto o el standard? o simplemente escribimos como queramos sin ninguna regla?
gracias.
tengo el codigo igual al profesor y tambien he levantado el proyecto en la rama de los recursos del proyecto y no me funciona en ningun caso. No entiendo la verdad.
Hola, Josue.
Comparte tu código para ayudarte
increible clase, tengo muchas ganas de usar los server components!
El SyntheticEvent es una abstracción del evento nativo del navegador. Esto le permite a React tener un comportamiento consistente en todos los navegadores.
Interesante. Aquí hay un recurso para profundiar un poco:
en next.js 16 los params y searchParams se reciben como Promise tarde horas tratando de solucionarlo.
He aplicado el principio de Responsabilidad Única (SRP) de SOLID al separar las funcionalidades en servicios distintos. En lugar de tener una sola función con dos responsabilidades, ahora tenemos dos funciones especializadas: una para obtener todos los productos y otra para obtener un producto específico. Esto mejora la mantenibilidad, legibilidad y escalabilidad del código.
import{ env }from"@/config/env"import{ shopifyUrls }from"./urls"// Función para transformar productos de la API a nuestro formatoconst transformProducts =(products: any[]):ProductType[]=>{return products.map((product: any)=>({id: product.id,title: product.title,description: product.body_html,price:parseFloat(product.variants[0].price),image: product.images[0].src,quantity: product.variants[0].inventory_quantity,handle: product.handle,tags: product.tags,}))}// Servicio para obtener todos los productosexportconst getProducts =async():Promise<ProductType[]>=>{try{const response =awaitfetch(shopifyUrls.products.all,{headers:newHeaders({'X-Shopify-Access-Token': env.SHOPIFY_ACCES_TOKEN})})if(!response.ok){thrownewError(`Error: ${response.status}`)}const{ products }=await response.json()returntransformProducts(products)}catch(error){console.error('Error fetching products:', error)return[]}}// Servicio para obtener un solo producto por IDexportconst getProduct =async(id: string):Promise<ProductType|null>=>{try{const response =awaitfetch(`${shopifyUrls.products.all}?ids=${id}`,{headers:newHeaders({'X-Shopify-Access-Token': env.SHOPIFY_ACCES_TOKEN})})if(!response.ok){thrownewError(`Error: ${response.status}`)}const{ products }=await response.json()if(products.length===0){returnnull}// Transformamos y devolvemos el primer producto (debería ser el único)const transformedProducts =transformProducts(products)return transformedProducts[0]}catch(error){console.error(`Error fetching product with id ${id}:`, error)returnnull}}```import { env } from "@/config/env"import { shopifyUrls } from "./urls"
// Función para transformar productos de la API a nuestro formatoconst transformProducts = (products: any\[]): ProductType\[] => { return products.map((product: any) => ({ id: product.id, title: product.title, description: product.body\_html, price: parseFloat(product.variants\[0].price), image: product.images\[0].src, quantity: product.variants\[0].inventory\_quantity, handle: product.handle, tags: product.tags, }))}
// Servicio para obtener todos los productosexport const getProducts = async (): Promise\<ProductType\[]> => { try { const response = await fetch(shopifyUrls.products.all, { headers: new Headers({ 'X-Shopify-Access-Token': env.SHOPIFY\_ACCES\_TOKEN }) }) if (!response.ok) { throw new Error(`Error: ${response.status}`) } const { products } = await response.json() return transformProducts(products) } catch (error) { console.error('Error fetching products:', error) return \[] }}
// Servicio para obtener un solo producto por IDexport const getProduct = async (id: string): Promise\<ProductType | null> => { try { const response = await fetch(`${shopifyUrls.products.all}?ids=${id}`, { headers: new Headers({ 'X-Shopify-Access-Token': env.SHOPIFY\_ACCES\_TOKEN }) }) if (!response.ok) { throw new Error(`Error: ${response.status}`) } const { products } = await response.json() if (products.length === 0) { return null } // Transformamos y devolvemos el primer producto (debería ser el único) const transformedProducts = transformProducts(products) return transformedProducts\[0] } catch (error) { console.error(`Error fetching product with id ${id}:`, error)returnnull}}
Wow me confundi un poco el mio no captura mis varaibles de entorno por que son de servidor tuve que agregar un una nueva variable de cliente en .env NEXT_PUBLIC_SHOPIFY_HOSTNAME
ademas me sale problema de cors.