This graph shows how many times the word ______ has been mentioned throughout the history of the program.
Hoy voy a explicarte cómo puedes utilizar Next.js con Strapi y qué es Strapi, por qué es interesante,
qué es un CMS, qué es un Hellless CMS, todo esto te lo voy a responder hoy, lo vas a entender,
vas a ver por qué es importante, por qué muchas empresas lo utilizan, por qué es interesante que tengas estos conocimientos
y vamos a hacer obviamente una aplicación de prueba desde cero, ¿vale?
Y la vamos a hacer con nuestros propios contenidos, podríais crear lo que queráis, podríais hacer un blog,
podríais hacer una tienda online, un periódico virtual, podéis, lo que se os ocurra, porque el límite es vuestra imaginación,
vais a poder crear vuestro propio contenido e incluso hacer relaciones de ese contenido, eso lo vamos a ver, ¿eh?
No os preocupéis, no os preocupéis. Lo malo que tiene Strapi es hospedarlo y eso lo vamos a ver, ¿eh?
Pero es totalmente open source. Strapi es un Content Management System, un CMS.
Un CMS es de lo más importante que pueda existir en el mundo del desarrollo web.
Un CMS significa Content Management System, un sistema de administración de contenido.
Y el más famoso de CMS que existe es WordPress, por si no lo sabías.
WordPress, que hace tiempo era como un sistema de blogs, o a la gente pensaba que era un sistema de blogs,
en realidad es un CMS, es un sistema de gestión de contenidos.
Y aquí es el más famoso, pero de lejos.
WordPress es el CMS más famoso jamás construido.
¿Por qué? Porque es verdad que al inicio podríamos pensar que era solo para blogs,
pero al final se pueden hacer tiendas online, se pueden hacer un montón de cosas, ¿no?
Y es el CMS más famoso y más utilizado a día de hoy, ¿ok?
Mira, el 43% de las webs del mundo están creadas con WordPress.
Blogueros, pequeños negocios, grandes empresas, prefieren WordPress para crear su página web,
con todas las alternativas y tal.
Pero, ¿cuál es el problema que ha tenido durante mucho tiempo WordPress?
Lo bueno y lo malo.
Lo bueno es que siempre ha tenido un sistema de plugins que ha permitido poder extender la funcionalidad de WordPress.
Lo malo es que siempre ha estado un poco encorsetado en su idea original,
que era el crear artículos, posts, comentarios, usuarios.
Es verdad que una cosa que han ido mejorando con el tiempo y ha evolucionado,
pero aún así todavía, ¿no?
Está ese corset, no está tan, tan, tan pensado todavía como para que la UI y todo esté pensado para crear cualquier cosa.
Ha mejorado mucho, sí que se puede hacer cualquier cosa, pero no llega al nivel de Strapi en ese sentido, ¿no?
¿Y qué es Strapi?
Entonces, ¿qué es lo que vamos a aprender hoy?
Strapi es un Headless CMS.
¿Y por qué le pone la coletilla de Headless, vale?
O sea, es un CMS, un sistema de gestión de contenidos, pero fíjate que pone Headless.
Y esto es súper importante también en el mundo de la programación web.
Cualquier cosa que quiera decir Headless, lo que quiere decir es que lo vas a poder utilizar.
No significa sin cabeza, es la traducción literal.
Cuando hablamos de Headless es que, digamos que prescinde de la parte visual, ¿vale?
No tienes la parte visual, no utilizas la parte visual.
En este caso, Strapi no está ligado a un frontend.
No tienes una página web donde tienes que ver el contenido sí o sí.
WordPress durante mucho tiempo fue un CMS, pero estaba ligado a la parte visual.
También estaba con el frontend.
Tenías un PHP donde tenías que mostrar los artículos y tal.
Eso también lo han mejorado y WordPress ahora te ofrece una API y lo puedes utilizar Headless, ¿vale?
Lo puedes utilizar sin esa parte del frontend.
Y Strapi siempre ha estado pensado directamente para que lo puedas utilizar de forma que lo conectes allá donde tú quieras.
Y que todo a través de la API lo puedas consumir, crear, actualizar, etcétera, etcétera.
Por eso se llama Headless, ¿vale?
Un Headless CMS porque es un sistema de gestión de contenidos, pero que no va ligado a un frontend.
Eso lo pones tú, ¿vale?
Eso lo vamos a crear nosotros y justamente lo vamos a crear con Nexies, ¿vale?
Sería un backend, claro, sería un backend.
Lo que pasa es que cuando hablamos de que es un backend, en este caso sí que tiene una parte visual.
Lo vamos a ver, ¿no?
Los backends normalmente no tienen una parte visual que te ayuda a crear y a gestionar el contenido.
Justamente por eso es la gracia de utilizar Strapi, ¿no?
Tienes la demo del sistema de gestión de contenido donde esto sería el dashboard.
En el dashboard podéis crear diferentes tipos de colecciones, podéis decirle las colecciones cuáles son los campos que tienen, todo.
Va mucho más allá de pensar que es solo un backend o que es simplemente una API porque lo que tenemos aquí es un CMS que vamos a poder crear visualmente todo nuestro contenido y esto nos va a generar automáticamente una API para poder consumir esto.
Con un sistema de roles, de permisos, plugins y un montón de cosas más.
Así que es brutal porque esto es increíble, increíblemente potente.
Es que es increíble.
Cualquier cosa que se te ocurra lo vas a poder hacer con esto.
Pero el problema es que obviamente hay que hospedarlo.
Si vais a pricing, vais a ver aquí que si ponéis self-hosted, claro, es gratis para siempre.
¿Cuál es el problema?
El problema es que lo tenéis que hospedar vosotros mismos.
Sí que es verdad que tiene una parte de enterprise que entonces os van a dar soporte y todo este tipo de cosas.
Pero bueno, eso es totalmente opcional.
Y luego tenéis la opción cloud que entonces sí que es de pago pero porque ya os lo está hospedando a vosotros.
Lo están hospedando por ti y ya se preocupan de todo el tema del servidor, base de datos y todo esto.
Voy a enseñaros también cómo podéis utilizarlo con GraphQL, ¿vale?
Pero hay millones de alternativas.
Podéis utilizar la que os dé la gana, ¿vale?
No las voy a listar todas ni las vamos a ver todas porque si no, no termina.
Así que vamos a crear nuestro proyecto y fíjate que ya nos lo pone aquí que nos dice npx createStrappy applatest.
Y aquí tendríamos el nombre de nuestro proyecto.
Abrimos aquí la terminal y voy a ponerlo todo en mkdir.
Ponemos nextStrappy, ¿vale?
cd nextStrappy.
Y aquí yo voy a crear ya directamente dentro del proyecto, voy a crear la parte de, voy a ponerle API, ¿vale?
Para tenerlo separado, lo que es la web, lo que es la API.
Vais a ver que no se puede en Vercel.
No se puede en Vercel porque estos necesitan a base de datos.
Igual el día de mañana hacen algún tipo de conector especial.
Lo que sí que se puede es integrar con un proyecto que tengáis en Vercel.
Pero no podéis desplegarlo en Vercel.
No funciona así, por desgracia.
De hecho es lo más complicado que tiene Strappy muchas veces.
Es el tema del despliegue.
Es un poco rollo.
Muy bien, pues creamos nuestro primer proyecto, createStrappyApp.
Y le decimos que lo cree en la carpeta API.
Y ya lo tendríamos por aquí.
Aquí nos dice, kickstart o custom.
Yo lo voy a hacer kickstart, porque así lo vamos a hacer más rápido.
Y esto por defecto lo que va a hacer es crearnos una base de datos SQLite.
Si lo ponéis custom, tendrías la opción de hacerlo directamente, lo podéis hacer con PostgreSQL.
Creo que con MySQL, con...
Hay diferentes bases de datos.
Pero yo os recomiendo que para el tema del desarrollo, especialmente para hacerlo en local,
lo hagáis con el kickstart y lo vais a hacer directamente con el SQLite.
Si no, podéis ponerlo en custom y directamente elegimos JavaScript o TypeScript, lo que queráis.
Y aquí tenéis PostgreSQL, yo voy a poner SQLite, que sería el por defecto.
FileName, este sería el sitio donde guarda por defecto la base de datos.
Y ya crearía nuestra base de datos.
Y ya está, ahora se pone a instalar las dependencias y tal.
La verdad es que tarda bastante la primera instalación.
Me sorprende.
Pero es que es un proyecto bastante grande.
Ahora cuando lo levantemos lo vais a ver.
Porque tiene la parte visual, pero también tiene toda la parte de backend.
En P&Rand, mira, entramos en API y ya tenemos aquí los scripts que vamos a ejecutar.
¿Vale?
Develop, build y Strapi.
Vamos a poner run, develop.
Y esto nos va a levantar en modo desarrollo nuestra aplicación de Strapi.
Ya nos va a pedir, nada más levantarlo, fíjate que nos está pidiendo los credenciales.
Porque vamos a tener que iniciar la sesión.
Vamos a tener un usuario que sea el administrador.
Aquí le ponéis el nombre, pues Durant.
Ponéis vuestro correo, el que queráis.
Le ponéis aquí la contraseña que os dé la gana.
A ver si le puedo sugerir contraseña.
¿Vale?
Esto es la local, aunque luego la podéis pasar también a producción, la que os dé la gana.
Y esto para que os envíe spam.
Le decís que no, no queréis spam.
Así que let's start.
¿Ok?
Ya le damos a actualizar.
Y ya es la primera vez que hemos entrado, ¿no?
Ya hemos entrado en el dashboard de nuestra aplicación con Strapi.
Al principio fue un poco parecido a WordPress, ¿no?
Tenemos que iniciar la sesión y ya nos pide un usuario que sea el que administre y todo esto.
El diseño es bastante bonito.
A mí me gusta mucho porque es sencillo, minimalista y claro.
O sea, lo cual está súper genial.
Ya lo primero que nos dice es crea tu primer tipo de contenido.
Esto es clave porque como puedes ver por defecto, el único tipo de contenido que tiene Strapi, lo podéis ver aquí, solo tiene un tipo de colección que es el de usuario.
¿Por qué?
Porque lo ha necesitado ya.
Ya ha tenido que hacer una colección del tipo usuario y nosotros hemos creado el primer usuario.
Pero ya está, está vacío.
Ni tiene artículos, ni post, ni productos, nada.
Eso depende de ti y tienes que empezar a crearlo tú a mano.
O sea, que lo que tenemos que hacer ahora, aquí, uno a uno, tendríamos que ir.
Y yo, por ejemplo, pues he pensado, ¿qué podríamos hacer?
Pues yo he pensado que podríamos hacer una aplicación que sea como de videojuegos.
Así que vamos a crear nuestro tipo de colección.
¿Ves que le pone aquí build a collection type?
Pues le vamos a dar, ¿ok?
Ya nos ha abierto aquí.
Mira, podemos ver el usuario, que está bastante interesante.
El usuario, estos son los campos que tendría.
Y este es el tipo del campo.
Nosotros le vamos a indicar cada tipo de campo.
Tenemos el username, el email, el provider, password, reset, password token.
¿Ves?
Y hay algunos que son boleanes, algunos que son relaciones.
Muy bien, pues vamos a crear nuestra primera colección.
Y aquí le vamos a llamar, yo que sé, video game.
¿Vale?
Video game.
Fíjate, fíjate que es importante que lo pongas el display name,
que sea en singular.
Igual que ellos han puesto el user, le han puesto en singular,
tú también el display name en singular.
Porque automáticamente ya te va a crear tanto el singular como el plural.
Y esto es importante para los endpoints que te va a crear en la API.
Así que no pongáis aquí video games,
porque bueno, lo que te va a pasar es que el singular te va a poner video games
y va a quedar un poco raro, ¿vale?
Así que video game.
Si lo ponéis todo junto, lo podéis poner así también,
aunque yo os recomiendo que empecéis al menos con una mayúscula,
pues lo podría así.
Si le ponéis una separación al display name, pues os pone un guión.
Así que lo que prefiráis, si queréis ponerlo todo junto y ya está.
Si ponéis una separación, os lo va a poner con un guión y punto.
Os lo va a slugify, ¿vale?
Slugify, que es lo que hacen con las URLs bonitas.
Aquí en Advanced Settings lo que podéis hacer es,
si queréis tener internacionalización,
que tal vez podéis tener traducciones,
lo cual es bastante potente que lo podáis tener en este CMS.
Y también si te permite crear un draft de cada entrada antes de publicarlo.
Lo voy a poner para que veamos ese sistema, ¿vale?
Y por ahora vamos a crear nuestro video game,
nuestro primer tipo de colección.
Así que ahora en los videojuegos tendríamos que describir
cómo es nuestro contenido.
¿Cuáles son los campos que queremos que tengan nuestros videojuegos?
Obviamente, pues va a tener aquí un title, ¿vale?
Y aquí puedes decirle si es un texto corto o es un texto largo.
En Advanced Settings le vais a poder decir
si es un campo que es requerido.
En este caso lo debería ser, ¿no?
Si es un campo único.
En este caso los videojuegos, pues por desgracia,
los nombres se pueden repetir.
Si tiene un máximo de longitud,
aquí le podríamos poner, oye, pues no me pongas
un título de videojuego que sea mayor de 150.
Y si tiene un mínimo, pues le vamos a poner uno.
Yo qué sé, no puede haber un juego que se llame vacío.
Y si es un campo privado.
En este caso no queremos que sea privado,
así que lo vamos a dejar.
Ahora le damos a Finish y ya tendríamos nuestro primer campo.
Vamos a seguir creando algunos campos, por ejemplo, yo qué sé.
Uno de que sea la fecha donde tenemos el launch, ¿no?
De qué fecha, cuándo se lanzó.
Puede ser una fecha del día, del día y la hora o de la hora.
En este caso tiene sentido que sea del día.
Y lo mismo, ¿no?
Podéis ver aquí otra vez si tiene un valor por defecto,
si es requerido, si es único.
Esto lo vamos a dejar vacíos.
Añadimos otro campo.
Ahora podríamos tener otro tipo texto.
O incluso, no solo hay uno de texto, también hay un Rich Text.
Esto es interesante si tenéis que crear contenidos como artículos,
que sean posts, texto, descripciones, lo que sea, ¿no?
Para poner negritas, cursivas.
Mira, lo vamos a hacer con Rich Text.
Y aquí le vamos a poner Description, ¿no?
Donde describamos cómo es el título, ¿vale?
Le decimos un Require.
Lo demás lo dejamos.
Finish.
Os voy a enseñar algunos interesantes.
Uno, el de imágenes.
Porque podéis tener imágenes y subir imágenes.
Aquí le vamos a poner Cover.
Y vamos a decir que solo se pueda subir una.
Pero podéis hacer que también se pueda subir más de una imagen.
Imaginaos.
Podríamos tener la portada del juego,
pero también podríamos tener screenshots del juego.
Y para eso dejaríamos el Multiple.
Y así podéis utilizarlo para crear carruseles, sliders y todo esto.
Yo le voy a poner que el Cover solo pueda haber uno.
Y le vamos a decir aquí, mira, cuáles son los tipos de media que se puede subir.
Lo puedes como restringir.
Así evitas que alguien arrastre algo que no sea una imagen.
Así que le dicen, no, solo pueden ser imágenes.
¿Vale?
Lo guardamos.
Uno bastante importante.
Un identificador único.
Fíjate que aquí, ves, puedes tener JSON, enumeraciones.
Puedes tener un montón.
Pero hay este que se llama Unique Identifier.
¿Para qué puede ser un Unique Identifier?
Más allá del identificador que ella tiene interiormente.
O sea, de forma interna, de forma privada,
cada uno de los elementos va a tener una ID.
Pero eso es privado.
Ahora, imagínate que nuestro videojuego queremos que tenga una página web.
Y por lo tanto, de cada videojuego, cada detalle, querramos entrar en la URL.
Pues lo que vamos a querer es crear lo que se le llama un Slack.
¿Qué es el Slack?
Por si no sabéis lo que es.
Y no tiene nada que ver con el juego del Metal Slack,
que me encantaba este juego.
Un Slack, cuando entráis a una página web, todos, ¿no?
Ya habéis perdido mucho dinero también.
Cuando vais a una página web, por ejemplo, a un blog,
¿veis esta parte de aquí?
Top, guión, cinco, guión, preguntas, guión, JavaScript.
Esta parte de aquí, esto es lo que se le llama el Slack.
Que es una forma bonita de poner el título como en la URL.
Y esto hace tiempo que hoy ya no se sabe si es verdad o mentira.
Era importante para Google.
Porque así tenía como semántica la URL, aunque era una URL única,
también tenía semántica.
Y como que Google decían que ayudaba al SEO de que te lo posicionaba mejor.
A día de hoy ya no sabemos si esto es verdad o mentira.
Dice, muchas veces he escuchado por parte de Google que dice que eso ya no es real,
que no importa lo que pongas en la URL.
Pero aún así es verdad que este tipo de URL bonita es mucho más amigable, ¿no?
Para compartirla, ver esto aquí en la URL, que no imagínate esto, ¿no?
Pues es un poco extraña.
Pero bueno, si os fijáis en Twitter, en twitter.com, si vais a Midudev, ¿vale?
Y os vais a cualquier tweet, vais a ver que lo hace así.
Y no pasa nada.
Seguramente si busco esto en Google, sale el primero, ¿vale?
O sea, que no pasa nada.
Así que estas URLs amigables, esa parte que tenemos en la URL se le llama Slack.
Y así podemos tener nuestro propio ID único también.
Podríamos decirle, mira, créame un identificador único.
Le vamos a poner Slack.
Podría llamarle SEO URL, le podéis llamar como queráis.
Y fíjate que pone Attach Fill.
Esto es a través de qué campo tendría que sincronizarse.
A partir del título.
En este caso es el título porque es el único que tiene sentido, ¿vale?
Pero con el título, cada vez que nosotros cambiamos el título, le va a crear automáticamente este identificador único directamente, ¿vale?
Y nosotros no vamos a tener que preocuparnos de nada.
O sea, ya veis la de cosas que tiene Strapi, que es espectacular, ¿eh?
Lo vamos a dejar todo esto vacío, ¿vale?
Le damos a Finish.
Y ahora vamos a crear nuestra primera relación.
Porque los videojuegos, en este caso nuestros videojuegos, ¿vale?
Importante, no se me olvide el save, porque esto es una cosa que da mucha rabia de Strapi y que ya te digo que tengas mucho cuidado.
Y es el hecho del save este.
Hay un save aquí escondido, arriba a la derecha, que hay veces que si no tienes cuidado, tú a lo mejor has hecho todos estos cambios y de repente te vas y lo pierdes todo.
Vamos a intentar acordarnos de darle al save.
Ahora hace un restart de todo el servidor.
¿Ves?
Ya hemos completado.
Y ya podríamos crear nuestro primer contenido.
Podríamos ir a Content.
Y aquí en Content, pues podríamos empezar a crear una nueva entrada de los videojuegos.
¿Ves?
Aquí le damos a Video Game y creamos una nueva entrada.
Y automáticamente, automáticamente, lo que ha hecho Strapi es crearnos una interfaz para que aquí podamos introducir cualquier información que tenga que ver con los campos que hemos hecho.
O sea, nosotros le hemos añadido el title y aquí tenemos un texto para añadir.
Le hemos añadido el launch, que era una fecha, y por lo tanto nos ha añadido esto para que pongamos una fecha.
Tenemos una descripción y aquí, hola, este juego es la bomba.
Y como le hemos dicho que sea rich, pues fíjate que lo podemos poner en negrita también, con markdown.
Y tenemos un modo preview o con markdown.
Le podemos arrastrar aquí una imagen.
Tendríamos aquí el slack que ha sido a partir del título.
Fíjate que si pongo Elden Ring, ¿vale?
Y le damos aquí a regenerar.
Fíjate que el slack lo ha generado automáticamente.
O sea, tremendo.
Tremendo.
Todavía no voy a crearlo porque voy a crear antes otra cosa, ¿vale?
Antes de crear mi primera entrada voy a crear otra cosa, ¿vale?
Salgo de aquí, luego lo creo.
Vamos a crear otro tipo de contenido solo para tener otro y para que veas.
Yo creo que una de las cosas más potentes que tiene Strapi.
Cuando creamos otra colección, vamos a poner aquí otra colección que le vamos a llamar Platform.
¿Por qué?
Porque cada videojuego va a salir en diferentes plataformas.
Por ejemplo, el Zelda sale en la Switch y el Uncharted sale en la PlayStation 5.
Y hay juegos como el Elden Ring que salen más de una plataforma.
Pues vamos a crear nuestro Platform donde vamos a tener la información de cada plataforma de los sistemas que existen.
Ahora, aquí en Advanced, ¿vale?
Esto lo ponemos así, ¿vale?
Creamos Platform.
Vamos a crear campos.
¿Qué campos vamos a tener?
Venga, vamos a crear el de Name, ¿vale?
Que sea short.
Vamos a decirle que esté required.
Este sí que podría ser único porque espero que no hayan dos PlayStation 5 en nuestro sistema de plataforma.
Lo podríamos crear.
Vamos a hacerlo, total, para que veamos cómo sería.
Incluso podéis poner un patrón de regex para evitar que alguien, yo qué sé, pues no se puede poner un título que empiece por punto o pues este tipo de cosas.
Lo podéis hacer con un patrón aquí y automáticamente ya lo evitaría.
Lo que es interesante es que estas validaciones también ocurrirían a nivel de API, ¿vale?
O sea, cuando la API, vais a ver que podríamos no solo leer la información sino también escribir la información.
Podemos tener roles, permisos de usuario para permitirles que creen con la API esto.
Y estas validaciones se harían también, o sea, que es que lo hace súper potente.
Vale, tendríamos el nombre, ¿qué más podemos tener?
Si todavía un boleano, un boleano que sea supported, ¿vale?
Para saber si todavía está soportado.
Vamos a ponerle, por defecto, vamos a ponerle que sea true, que esto require, ¿vale?
¿Qué más podemos decir?
La compañía, ¿vale?
Vamos a decir company.
Y aquí tendríamos, pues sería Sony, lo que sea, ¿no?
Sería diferentes.
Le podemos poner, mira, la company.
La company, ya que estamos, podríamos ponerlo con enumeraciones, ¿no?
La company, podríamos decir que puede ser Sony, podríamos poner Nintendo, Microsoft.
Obviamente existen más compañías que tienen consolas, yo que sé, SNK.
Hay un montón de compañías que han tenido consolas.
Pero, imagina que tenemos aquí toda la lista.
Podríamos poner la enumeración de forma que siempre nos aseguremos que tiene que seleccionar una de la lista, ¿vale?
Y aquí, por defecto, vamos a decir que no es requerido y ya está, ¿vale?
Le vamos a poner finish.
¿Qué más?
¿Cuándo se lanzó?
Voy a poner cuándo se lanzó, ¿vale?
Launch.
Vamos a poner el día de cuándo se lanzó, ¿vale?
Ya tenemos las plataformas y los videojuegos.
Y ahora te voy a enseñar una de las cosas, yo creo, más brutales, geniales y tremendas.
Para que no tengáis que preocuparos nunca más de la base de datos.
O sea, lo que es genial es que ya no vais a tener que preocuparos.
A ver, no vais a tener que preocuparos.
Si utilizáis Strapi, lo bueno es que ya os va a hacer de base de datos automáticamente.
Las relaciones entre ellas las vais a poder hacer.
Imaginate una tienda virtual.
Pues una tienda virtual vais a poder tener categorías, productos y crear relaciones de que los productos estén relacionados a una categoría.
E incluso a más de una categoría, ¿vale?
O sea, es tremendo.
¿Y cómo se hace esto?
Pues mira, imagínate un videojuego.
Un videojuego puede salir en más de una plataforma.
Así que vamos a, en el videojuego, vamos a crear un campo y le vamos a decir, ¿vale?
Vamos a crear una relación.
¿Veis aquí?
Relación.
Creamos una relación y le decimos, un videojuego, ¿vale?
El campo le vamos a llamar platform.
Un videojuego, ¿cuántas plataformas puede tener?
Y aquí es que lo ves clarísimamente, ¿vale?
Un videojuego tiene una plataforma.
Esto es una relación uno a uno.
No es el caso, porque los videojuegos, es verdad que existen algunos exclusivos, pero sabemos que hay juegos que pueden estar en más de una plataforma.
Entonces, la relación correcta sería un videojuego pertenece a más de una plataforma.
Esta sería la relación correcta.
Pero está muy chulo porque justo con estos iconitos se entiende súper bien.
Se entiende muy bien cómo son las relaciones.
Por ejemplo, podrías tener diferentes, otro tipo de relaciones, ¿no?
De decir, de que usuarios, por ejemplo, usuarios, relaciones, uno a muchos.
Por ejemplo, un usuario puede seguir a muchos usuarios, pero otro usuario puede seguir a otros usuarios, ¿no?
Ahí tendrías otro tipo de relación.
Es muy interesante porque además cada vez que le dais a uno dice, un videojuego tiene una plataforma.
Un videojuego tiene y pertenece a una plataforma.
Un videojuego pertenece a diferentes plataformas.
Una plataforma tiene diferentes videojuegos.
Luego tendrías videojuegos, tienen y pertenece a diferentes plataformas, ¿no?
O sea, que tendríais diferentes.
Aquí lo que podemos decir es que el videojuego pertenece a diferentes plataformas.
Está bastante bien porque así muchas veces las relaciones son un poco rollo,
pero con esto lo vais a entender súper fácil y no vais a tener ningún problema,
no vais a tener que preocuparos de crear relaciones.
Lo fácil que es crear las relaciones.
Hombre, así sí, Lisa. Así sí.
Lisandro. Perdón, ¿Lisa o Lisandro? No sé.
Me cuesta bastante el hecho de decir, pero ¿de quién es la relación?
O sea, no de qué es la relación.
Cuando tienes que hacer a mano, el problema es que realmente puedes tener
el cómo relacionas las llaves para tenerlo claro.
Pues aquí en este caso, el correcto videojuego, yo creo que el correcto sería este, ¿vale?
¿Por qué? Porque tenemos un videojuego que puede ser de diferentes plataformas, ¿no?
O sea, un videojuego puede tener más de una plataforma, ¿ves?
Esta puede tener tres plataformas, este a este.
Este sería el correcto, ¿vale?
Los videojuegos pertenecen a diferentes plataformas, sería many to many.
O sea, puede tener diferentes videojuegos a diferentes plataformas.
Esta sería la relación que nosotros necesitamos utilizar, ¿vale?
Así que le damos a Finish, le damos a Save, que no recordemos, y ya está.
Ya reseteamos.
Ya con esto nos olvidamos de las relaciones, ya lo tenemos.
Y ahora, con lo que hemos hecho, que no hemos tocado todavía código, ya sé que parece raro,
vamos a ver para qué ha servido lo que hemos hecho.
Lo primero es que tenemos que crear algo de contenido.
Así que nos vamos al Content Manager, vamos a crear aquí, por ejemplo,
mira, Platform, vamos a crear, vamos a tener PlayStation 5, todavía soportada,
la compañía Sony, ¿veis el Enum? Así como estaría.
Luego tendríamos, yo qué sé, no me acuerdo cuándo salió, ¿eh?
Me voy a inventar todas las fechas.
Y bueno, aquí tendríamos que crear relaciones, pero ahora mismo no tenemos la relación.
Así que nada, aquí ya nos dice de testear la API.
Lo hacemos ahora en un momentito, ¿vale?
La publicamos, ya teníamos la PlayStation 5.
Bueno, pues podríamos seguir creando, ¿ves?
PlayStation 5, Xbox Series X, no las voy a crear todas, ¿vale?
Voy a crear solo las tres más importantes.
Vamos a poner esto del 2018, 19, no me acuerdo de cuándo es realmente.
Importante, hay que publicarla porque si no se queda en draft.
De hecho, lo vais a ver, ¿vale?
Fijad la diferencia.
Esta la he dejado en draft hasta que no la publicamos, no estaría disponible, ¿vale?
Así que la vamos a publicar.
Esto lo podéis cambiar como hemos visto antes.
¿Qué más?
Vamos a poner aquí Nintendo Switch.
Bueno, Switch, vamos a llamarle Switch, ¿vale?
Todavía soportado.
Esto es de Nintendo.
Y esta es más viejita, vamos a poner que es del 2017.
No me acuerdo, ¿eh?
¿Cuándo es?
La publicamos.
Vale, ya tenemos tres plataformas.
Luego, ¿qué más podemos hacer?
Ahora, en videogame, vamos a crear videojuegos.
Vamos a poner aquí Elden Ring, ¿vale?
El lanzamiento, no me acuerdo si fue en 2022.
Es un juego en el que te matan cada dos por tres y te dan ganas de explotar el mando contra la pared.
Te matan cada dos por tres.
Esto lo vamos a poner en negrita para que luego a ver cómo sacamos esta información.
La verdad es que nunca la había probado.
Mira, cover.
Vamos a Elden Ring, cover.
Vale, vamos a buscar la portada.
Por ejemplo, esta, ¿vale?
Escritorio.
¿Ahora?
Ahora sí.
Vale, pues fijaos que ahora es como que está subiendo esto, ¿vale?
Esto es un poco truco.
O sea, a ver, esto ahora en local todo funciona, todo es mágico.
Pero cuando lo desplegamos, tenéis diferentes opciones para que esto funcione.
Uno, lo podéis hacer en el propio servidor.
Es un poco tricky, ¿no?
Tenéis que tener disco, persistencia, permisos, un montón de cosas, pero se puede hacer.
Otra cosa, existe un plugin de Cloudinary que no lo vamos a llegar a hacer hoy,
pero que también funciona y lo que hacéis es que las imágenes se suban a Cloudinary.
Cloudinary, que ya lo hemos utilizado aquí, tiene un free tier que funciona bastante bien
y yo seguramente sea la que más os recomiendo.
Porque Cloudinary, lo bueno que tenéis con esto es que lo tenéis totalmente separado de vuestro hosting.
Si el día de mañana os cambiáis de hosting, pues bueno, lo bueno es que lo tendréis en Cloudinary,
lo tendréis totalmente optimizado y ya lo tendréis bastante bien.
Y total, son 25 créditos que si no me equivoco daban para 25 GB de almacenamiento o 25 GB de bandwidth.
Hay plugins de todo tipo, también para subir a Amazon, hay un montón.
Pero bueno, yo recomiendo el de Cloudinary, que no está nada mal.
Ya tenemos el de Elden Ring, ¿vale? Finish aquí, vamos a hacer a regenerar esto, que se ha generado mal.
Y aquí en Platform, fijaos que tenemos ya las relaciones, pues le podemos decir que esto ha salido en PlayStation 5,
pero también ha salido en Xbox Series X, ¿veis? Tiene dos relaciones, tiene dos relaciones.
Así que nada, guardamos, publicamos y ya tendríamos nuestro primer juego.
Vamos a crear dos juegos más, ¿vale? Para tener una cuanta de información.
Vamos a poner aquí el Zelda Tears of Kingdom, que esto no me acuerdo dónde se lanzó, pero yo creo que, no sé, en mayo.
Es el Breath of the Wild suficiente, ¿vale?
Entonces, Tears of Kingdom, cover.
Le vamos a poner la cover, qué bonita la cover, ¿eh?
Pero es que, vale, venga, upload, ok, finish.
La relación es que estos son los de Switch, el Slack parece que está correctamente, guardamos y publicamos.
Y vamos a poner uno más, ¿cuál podríamos poner?
¿Cuál? Ay, del Elden Ring, no puse la fecha en la que se lanzó.
¿Qué más? ¿Cuál? ¿El FIFA?
El FIFA, FIFA.
A ver, uno que sea de Xbox Series X.
God of War, venga, God of War.
God of War Ragnarok.
Un juego que paseas con tu hijo mientras nórdicos.
Y hay lobitos por ahí.
God of War Ragnarok.
Venga, hacemos este y ya seguimos, ¿vale?
Y hacemos lo de la API, que está muy chulo.
Vale, esto lo arrastramos por aquí.
Ahí tenemos nuestra imagen.
Subimos, finish, vale, la reacción.
PlayStation 5, save, publish.
Ya tenemos tres, ¿ok?
Ahora vamos a videogame.
Tenemos tres de nuestros maravillosos videojuegos.
¿Y para qué ha servido todo esto?
Será la pregunta del millón, ¿no?
¿Para qué ha servido todo esto?
Fijaos en la URL.
Tenemos localhosts, dos puntos, 1337, ¿vale?
Pues esto, si intentas entrar por defecto, la URL lo que te aparece es esto de aquí, ¿no?
Te aparece Open the Administration.
Esto lo puedes hacer porque está en modo desarrollo.
Si fuese en modo producción, esto no aparece así.
Este botón no aparece, ¿vale?
Luego aquí ya podríamos empezar a acceder a la API, ¿vale?
A la API.
La API, tenemos que decirle a dónde queremos ir.
¿Cómo tenemos que saberlo?
Bueno, pues aquí, cuando hemos creado videogame en el Content Type Builder, este videogame,
cuando hemos puesto este videogame, si te acuerdas, nos decía cómo iba a ser la API.
De hecho, podemos ir a Settings, aquí, a Roles, si no me equivoco, Public, y aquí tenemos
los permisos de todas las cosas que hemos hecho, ¿no?
O sea, si hemos creado videojuegos, ¿ves?
Videojuegos.
Y nos dice, define aquí las acciones para la API de videojuegos.
Le vamos a dar un clic, le vamos a dar, por ejemplo, al Find, ¿vale?
Lo voy a quitar, pero ves aquí que te dice Get API Video Games.
O sea, ya nos está dando el Endpoint que justamente vamos a tener.
Pues esto lo vamos a utilizar aquí y vas a ver que nos va a dar un problema, pero tiene sentido.
Vamos a ponerlo y, ojo, me ha dado un error, pero es algo diferente.
Me dice, forbidden error.
O sea, me está dando un error de que está prohibido, no de que no lo encuentre.
Fíjate la diferencia entre este, ¿no?
Que está en 404 y aquí, en Video Games, me está dando un 403, ¿no?
Me está diciendo un forbidden.
Y es que, por defecto, todos los permisos son privados.
O sea, nadie tiene acceso a nada, excepto tú como usuario administrador, pues tienes acceso
a cambiar y tal, ¿no?
Por defecto, no hay nada público, lo cual está súper chulo y súper importante.
Tenemos que ir uno a uno, voy a quitar esto, tenemos que ir uno a uno para ir cambiando
los permisos.
Por ejemplo, de los videojuegos, fíjate, aquí en Video Juegos tenemos crear videojuegos,
borrar videojuego, encontrar videojuego, encontrar un videojuego o actualizar.
Y en Permisos tendríamos los permisos a nivel público, público, estos serían los usuarios
que no han estado autentificados o los autentificados.
Porque también con Strapi, que hoy seguramente no nos va a dar tiempo seguro, podéis iniciar
sesión.
¿Ves?
Aquí tenéis Providers y fijaos todos los providers que podéis configurar.
Podéis utilizarlo con GitHub, Google, Instagram, LinkedIn, Microsoft, Patreon, Reddit, Twitch,
Twitter.
Podéis iniciar sesión con todo esto, incluso con el email, ¿vale?
O sea, ya te vienen todos los providers preparados para que puedas iniciar sesión.
En este caso, nosotros no vamos a hacer nada de, no lo vamos a hacer porque no va a dar
tiempo, pero vamos a ver, ya sabéis que va a tener un sistema de roles y que por cada
rol vais a poder decirle qué permisos tiene, lo cual es espectacular.
De hecho, veis, aquí tenéis diferentes roles, autor, editor, superadmin, los usuarios que
se habrían registrado en este caso, yo que soy superadmin.
O sea, tenéis un montón de roles ya previstos y preparados para utilizarlos.
Ahora, uno de los roles más importantes es justamente el de public, el público, el
que todo el mundo pueda leer.
Así que en public lo que vamos a darle es permisos, por ejemplo aquí, de find y find
one, para al menos la gente pueda leer la API para encontrar la información que queremos.
Solo encontrarla.
No le vamos a dar un permiso de create porque podrían empezar a crear APIs y lo podría
hacer utilizando la API haciendo un post.
Pero bueno, vamos ahora por ahora a hacer el get, lo guardamos, ¿ok?
Y fíjate, tan fácil como esto, actualizamos y ya tenemos nuestra API con nuestros permisos,
con nuestros atributos, con toda nuestra información.
Fíjate que tenemos aquí el title, launch, description, slack, cuándo se ha creado, cuándo
se ha actualizado, cuándo se ha publicado.
Y esto lo tenemos aquí para los tres videojuegos.
Este es el uno, este es el dos y este es el tres.
Hemos creado una API en un momento visualmente súper fácil, ¿ok?
Y ha creado la API, la base de datos, lo ha creado todo con nosotros.
Un saludo.
Gracias por todo.
Gracias a ti, José Luis.
Gracias, amigo.
Esto tiene muy buena pinta, pero no echáis en falta algo, ¿vale?
La gente me dice, ¿y la imagen?
¿Y la imagen?
¿Solo la imagen?
¿No falta algo más?
La relación, efectivamente, también falta la relación.
Falta también la plataforma.
O sea, nosotros cuando hemos creado el contenido, si os fijáis, teníamos en videogame, teníamos
la imagen y también teníamos las plataformas.
Y no están, no están, ¿vale?
Por defecto, Strapi lo que hace es intentar optimizar el output, digamos, ¿no?
La idea es autoincremental.
No le has dado permisos, ¿vale?
Ahora lo vamos a ver.
Hay un poco de todo.
Hay un tema de permisos y hay un tema de diferentes cosas.
Vamos con lo primero.
La pregunta del millón.
Tenemos la API, pero ¿qué pasa si queremos que la API nos dé menos información, ¿no?
Porque, por desgracia, aquí podemos ver que me lo ha devuelto todo.
Y a lo mejor yo solo quiero el title y yo solo quiero el title y el slack, ¿vale?
Imagínate.
Bueno, pues esto es maravilloso porque Strapi, por defecto, ya te da un sistema de filtros.
No solo para filtrar y para buscar, yo qué sé, decir, para el slack que sea igual a Elden Ring,
que eso lo veremos después, me devuelves todos los elementos, que el slack sea igual a Elden Ring.
Eso lo tiene.
Pero también puedes filtrar qué campos son los que quieres tener.
Por ejemplo, puedes poner fields.
Le dices que en el campo 0 vamos a tener el title.
Y le dices fields y en el campo 1 vamos a tener el slack.
Solo con esto, fíjate, ya hemos optimizado la API de forma que hemos seleccionado cuáles son los campos que queremos que nos devuelva.
Ahora con esto ya no nos devuelve todo.
Y esto ya está hecho, no tenemos que hacer absolutamente nada y ya está.
Aparte de esto, volvemos a lo de antes, ¿vale?
Ahora lo tenemos todo otra vez.
Nos faltan cosas aquí.
¿Qué nos falta?
La imagen y la relación.
Existe también, igual que tenemos el filter, el filter, el fields, igual que tenemos el fields,
también tenemos un query param que se llama populate.
Y el populate es como rellenar.
Relléname la información que te pida.
Si le pones asterisco, lo que va a intentar es rellenarte el máximo de información que pueda con las relaciones que tengan estos elementos del contenido.
Así que ahora le vamos a poner un asterisco para que intente rellenarlo todo lo que pueda, ¿vale?
¿Qué ha pasado aquí?
Pues que ahora de repente, al decirle que me ponga un populate con el asterisco, ahora me ha añadido el cover.
Que ahora sí tiene la información data y tiene sus atributos y aquí tiene pues un montón de cositas.
Con la URL donde podemos encontrar la imagen.
Con el populate lo que estamos consiguiendo es decirle, oye, me tienes que rellenar la información de todas las relaciones que tienes.
¿Qué pasa?
Que el cover, aunque aquí se ve como un tipo de contenido, el cover no deja de ser como una relación a una colección interna que digamos tiene Strapi.
Por eso le tenemos que poner aquí en el populate que lo haga.
Pero todavía no aparece la plataforma, ¿verdad?
Todavía no aparecen todas las informaciones y esto es porque no tiene permisos.
Vamos a necesitar que el poder, el rol de public tenga permiso de lectura también para las plataformas.
Porque si no, no va a ser capaz de extraer esa información, ¿vale?
Así que en platform también le vamos a poner find y find one.
Fijaos que ahora si le doy al populate y vuelvo a guardar, ahora sí que tengo las relaciones con las plataformas, ¿vale?
Así que tenemos ya la cover y las plataformas.
Para que nos hagamos una idea un poco de la potencia que tendría con esto, podríamos decir, claro, ahora cuando has hecho el populate, fijaos toda la información que sale.
Pues podríamos decir, mira, el populate de platforms, o sea, podríamos ser muy específico.
En los campos, en el cero, me vas a poner la id, ¿vale?
Y esto mismo, pero con el siguiente campo, por decir otro, lo quiero con el name, ¿vale?
Para saber el juego.
Entonces vamos a sacar la id y el name.
Y así vamos a hacer un populate para que no ocupe tanto, ¿no?
Si lo he puesto bien, ¿veis?
Ahora solo recupero la id y el name.
Se hace todo a través de la url.
Esto te puede gustar más, te puede gustar menos, pero la verdad es que es una forma bastante interesante de al menos tener una forma de evitar enviar toda la información, incluso cuando tenemos esto del populate.
Claro, ¿veis?
Aquí en este caso ha desaparecido el cover, que también lo podríamos añadir, ¿no?
Teníamos que hacer populate del cover y en el fields el cero y podríamos decirle que nos devuelva aquí, a ver si me acuerdo cómo era antes, no me acuerdo si era la url, ¿cómo era esto?
O le podemos decir que nos devuelva todo.
A ver, populate, a ver si tenemos attributes, url, ¿vale?
Pues url, ¿vale?
Y ahora al menos tendríamos la url.
Bueno, de hecho veo que la id te la da siempre por defecto, o sea, que no haría falta hacer este populate que he hecho aquí.
Esto lo puedo quitar y así lo simplificamos, ¿vale?
O sea, que podemos poner aquí name y así ya tendríamos una llamada más sencilla, ¿ves?
Tendríamos aquí el name de cada plataforma y el atributo de la imagen y ya estaríamos mejorando un poquito el rendimiento porque no lo estaríamos devolviendo todo.
Todo esto lo podéis modificar a otro nivel.
De hecho, vamos a hacer algo más interesante todavía para que veáis como de potentes Strapi.
Mirad, tiene un sistema de plugins que es brutal, ¿vale?
¿Veis?
Plugins y aquí tenéis el marketplace.
En el marketplace es que esto no os lo acabáis, ¿vale?
Tenéis desde, mira, la creación de un identificador único que no sea con el id incremental.
Esto lo podéis hacer.
Para un calendario, para poder hacer builds en Cloudflare Pages.
Hay un montón.
También hay una que es con GraphQL.
Y podéis añadir endpoints de GraphQL directamente.
Aquí, fijaos aquí que podéis ver cuántas instalaciones se ha hecho, cuántas estrellitas tiene.
Le dais aquí, copy install command, ¿vale?
Os vais aquí y directamente, pues, pegáis el comando de install del plugin.
Hacemos esto, lo instalamos.
Tarda un ratito.
Fíjate que he instalado esto, se ha actualizado automáticamente, ¿vale?
Ha detectado esto, que ha habido algún cambio.
Y ahora, si vamos, si no me equivoco, GraphQL, ya tenemos un playground con GraphQL, ¿vale?
Nos ha hecho un playground con GraphQL en un momento.
Y fijaos que ya tenemos aquí autocomplete y podríamos poner aquí el videogame.
Bueno, videogames.
Y aquí, pues, sacar de data.
Podríamos sacar los atributos.
Y tendríamos el title.
Le damos al play y aquí lo tenéis.
Ya tenemos un servidor con API de GraphQL en un momento.
También podéis sacar a la vez de platforms también, ¿eh?
También lo podéis sacar de platforms.
Podríais sacar, pues, de cada platform el attribute, ¿vale?
Claro, esto no lo podéis sacar así porque no lo está entendiendo, ¿eh?
Pero aquí, aquí sí que debería funcionar.
Si sacamos de data, claro, porque de attributes y sacamos el name, que sea como el populate, ¿vale?
Aquí sí que tendríais como un populate.
Sería como el populate, pero aquí no tenéis que indicar el populate.
Aquí directamente en atributos ya tenéis la plataforma.
En la plataforma podéis sacar el name y ya tendríais aquí toda la información.
Y os está devolviendo exactamente lo que necesitáis.
O sea, brutal.
Vamos aquí con el esquema, cosa muy interesante.
Aquí en el esquema tenéis todos los tipos, todos los tipos que podríais tener aquí dentro del left upload file y tal.
Y podríais buscar incluso el de videogame, ¿vale?
El de videogame también lo tenéis por aquí para que podáis filtrar por videojuegos, hacer el input, todo esto.
Y en docs tendríais todas las queries post que podéis hacer.
O sea, ya tenéis documentada toda vuestra API y la habéis hecho todo con UI.
Tremendo, ¿no?
En un momento.
A ver, todo esto está muy bien.
Está muy chulo, la verdad, pero yo creo que lo más interesante es que veamos cómo lo podríamos utilizar rápidamente con Next.js.
Así que vamos a hacer un npx create next app latest.
Vale, vamos a poner web.
No quiero esto.
Esto sí.
Esto sí.
Esto también.
Sí, con el app router.
No quiero configurar esto.
Vamos a instalar y vamos a crear un proyecto con Next.js.
Esto es para que veáis rápidamente cómo podemos utilizar los server components para conectar todo lo que hemos hecho, que no está mal, de Strapi, que se pueden hacer cosas muy brutales, con Next.js.
¿Vale?
Cómo funciona la API y cómo lo tenemos que hacer.
Nos vamos a web.
Hacemos npn run dev.
Esto nos va a levantar en localhost 3000 nuestro proyecto de Next.js.
Como tarda.
Y vamos a levantar la web aquí también.
¿Vale?
Muy bien.
Vamos a quitar todo esto que no necesitamos.
Esto es como lo que viene por defecto.
Esto es la imagen fuera.
Y ahora vamos a crear para tener esto preparado.
Vamos a poner .env, .env, .local, .env, .local.
Y aquí podríamos tener la API URL.
Claro, cuando estamos en local, obviamente, vamos a querer que tire a localhost 1337 barra API.
Y aquí vendrá lo que viene después, ¿no?
Videogame o lo que sea.
Esto lo podemos cambiar como variable de entorno.
Y aquí, pues, ya tenemos una sync function, get games.
Ahora me he acordado de un posible problema que vamos a poder tener, ¿eh?
Pero bueno, ahora lo probamos.
Fetch, vamos a traernos, vamos a crear aquí en app, vamos a config.js.
Y vamos a importar, no, vamos a exportar la constante API URL, que esto lo sacamos del process.e, ¿vale?
Estamos leyendo la variable de entorno que tenemos aquí, en este config, y la estamos exportando automáticamente.
A mí me gusta hacer esto para evitar tener que llamar constantemente en todos mis ficheros el process.e.
Lo hago en un fichero, exporto la variable de entorno y ya me he olvidado.
¿Que aquí quiero utilizarlo?
Pues no pasa nada.
Hago un import de la API URL, ¿vale?
Lo importo desde el config, pero no hago esto que sé que muchas veces os gusta hacer,
de process.e, .api, URL, y luego llenáis todo vuestro código del process.e.
Pues así lo evitáis y os queda más limpio, lo tenéis en la configuración.
Y si el día de mañana, pues esto cambia por lo que sea, pues lo tenéis que tocar en un sitio.
Que muchas veces estamos con solid, clean code y la madre que nos parió,
y las cosas que el patrón módulo es el que tenemos al pobre más descuidado.
Vale, pues API, video games.
Mira, voy a utilizar este de aquí.
Ahora mismo me lo voy a copiar, luego lo extraeremos para tenerlo un poquito mejor.
Por ahora lo vamos a tener aquí.
Si res.key está mal, hacemos un throw new error y le decimos aquí que ha habido,
ups, something went wrong.
Y si no, pues vamos a extraer la data de await res.json y devolvemos data, ¿vale?
Ah, vale, aquí me ha faltado una wait, ¿vale?
Por eso me había puesto esto.
Perfecto.
Y aquí, como esto es un React Server Component, por defecto, en NextDS13,
cuando utilizamos el app router, todos los componentes por defecto son React Server Components.
Eso significa que por defecto solo se van a ejecutar en el servidor.
Así que podemos hacer, y debemos hacer, llamadas asíncronas dentro del componente.
¿Por qué?
Porque así es como vamos a hacer el fetching de datos.
Así que aquí vamos a poder hacer, recuperar el games, the get games.
Y aquí, pues, yo que sé.
Vamos a poner por ahora esto, games map, game.
Vamos a poner aquí game.
Por ahora solo esto.
Al menos para ver que esto saca algo.
Console lock games.
Esto seguramente va a dar un pete.
Ahora os explico por qué.
Justify Between, este lo vamos a quitar, que no tiene mucho sentido.
Hemos creado un método asíncrono para llamar el fetch de nuestra API, que ahora mismo tenemos el localhost.
Vamos a recuperar todos los videojuegos que tenemos.
Y también hacemos el populate para tener la información tanto del nombre de la plataforma,
o sea, si es PlayStation, Xbox o lo que sea, y para tener la carátula, ¿vale?
La URL de la carátula.
Luego, si no está bien la respuesta, pues, le devolvemos un error ahí a saco.
Si está bien, vamos a recuperar data, porque fijaos aquí que tenemos un objeto con data,
que además también tenemos metadata, que luego si nos da tiempo a hacer la paginación, pues, también lo veremos.
Así es como recuperamos los juegos.
Vamos a ver si esto ha funcionado.
¿Vale?
Vale.
No pasa nada.
Hay un error.
Hay un error.
Hay un problema.
No pasa nada.
¿Qué es lo que pasa?
Hay un problema.
¿Veis que pone type error, fetch fail y tal?
A veces, a veces, y esto me lo he encontrado muchas veces con Strapi, el localhost en macOS no funciona.
¿Por qué?
No tengo ni idea.
No tengo ni idea.
Es como que, no sé si es un tema de cabeceras, no sé si es porque utiliza la IP versión 6,
pero el tema es que este localhost no lo encuentra bien.
Entonces, tenéis que utilizar la IP de localhost.
Si utilizáis esta IP, va a funcionar correctamente.
Yo creo que es un tema de la IP 6.
Creo que es por eso.
No lo sé, ¿eh?
Es un tema de macOS, porque en otros sitios es que funciona.
Pero cambiando esto por la IP, ya funciona sin ningún problema.
Si probáis en Windows, no vais a tener problema.
Pero bueno, lo digo para que lo sepáis, porque yo me he encontrado esto alguna vez.
Ahora ha funcionado, pero fíjate que me dice que el objeto no es válido, ¿eh?
Normal.
Normal y corriente.
Esto es porque he puesto aquí el game a saco.
A ver, este games, este console.log aquí, vamos a poner aquí el juego, ¿vale?
Al menos por ahora.
Vamos a poner aquí la key con el game.id, ¿vale?
¿Ves?
Tengo tres juegos.
Todavía no sale la información.
No sé por qué no me sale el console.ninja este.
Es que aquí, con el console.ninja, me debería decir restart console.ninja.
Pues no.
No me lo está...
Este no me lo está pillando.
Y está entrando ahí, ¿eh?
De hecho, aquí sí que veo el console.log, pero aquí no me lo está...
No sé por qué de...
Bueno.
Total.
Que aquí podemos ver cómo es el objeto, ¿vale?
Así que no hay problemas.
Mira.
Tenemos la id, que eso lo vamos a utilizar como la key.
Así que aquí, perfecto.
Vamos a entrar para mostrarlo más o menos bien en un momento.
Y no me voy a liar con la UI.
Flowbyte, por si no lo conocéis y sabéis que es Tailwind.
Tailwind, al final, es un framework CSS que está muy chulo, pero es un rollo tener que estar escribiendo todos los classnames.
Flowbyte es un catálogo de componentes de copiar y pegar muy fácil que puede hacer que hagáis UIs muy rápidas en un momento.
Por ejemplo, mira, me voy a copiar esta, que tiene buena pinta.
Pondremos la cover aquí y así podremos enseñar en un momento la información.
Vamos a poner esto aquí, ¿vale?
Lo vamos a pegar.
Este image se me queja porque lo tenemos que cerrar aquí, ¿vale?
Y luego aquí, este link, vamos a poner que sea un link con la key GameID.
El link es para tener un enlace que haga SPA, ¿vale?
Así que este link lo vamos a importar de NextLink.
Y aquí se queja de que debería utilizar el componente image de NextGS.
Pero, ¿qué pasa? Que el componente image de NextGS tiene mucho peligro.
Entonces, tiene peligro porque es de pago.
Entonces, dependiendo con qué lo hagas, te puedes hablar ahí infinito.
Lo vamos a evitar. Voy a quitarlo en el slim para que no se nos queje más.
Que está muy bien porque optimiza, ¿vale?
Es importante que si realmente lo vais a querer utilizar, lo utilicéis en algún sitio,
pero que no utilicéis constantemente porque luego puede salir cara la cosa.
Vale, ya teníamos aquí un poquito la información.
A eso nos faltaría cambiar el título y todo esto.
Por ejemplo, aquí vamos a poner el título de nuestro videojuego que tendríamos en
game.attributes.title y aquí tendríamos el game.attributes.description.
Que esto también lo podríamos sacar de otra forma, ¿eh?
Lo podríamos sacar o directamente podríamos al menos hacer aquí attributes
para no tener que estar repitiendo constantemente y también sacar aquí la idea.
Lo simplificaría un poquito más, ¿vale?
O podríamos llegarlo un poco más y quitar este return directo y hacer la desestructuración
de aquí de title y todo esto.
Pero bueno, en este caso, para que más o menos nos hagamos a la idea, ya lo tendríamos.
Vale, esto lo ponemos por aquí.
Los class vamos a ponerlos como classname, que es la forma correcta en React.
Y aquí en esta imagen, aquí hay un problemilla.
Bueno, no es un problema grave, pero hay un problemilla.
Porque aquí no podemos utilizar attributes.
Y aquí el attributes.cover.data.dat.atributes.
Que la verdad es que es un poco rollo, ¿eh?
.url, ¿no?
Esto es un poco rollo.
Y aquí tendríamos dos opciones.
Una, mapear este data correctamente para simplificar cómo tenemos que acceder a esta información,
que yo creo que sería lo más correcto.
El hecho de mapear los datos para evitar tener que hacer esto aquí dentro de tus componentes
y todo esto, yo creo que eso sería lo correcto, ¿no?
Siempre que podamos, este tipo de cosas, además, la podéis separar en algún, no sé,
en una carpeta, aquí mismo, ¿no?
Podéis poner services, poner aquí videogames.js.
Y ya directamente esto lo exportáis y podríais mapear este data con el tipo de objeto
que realmente queréis utilizar, ¿no?
Entonces, importaríais aquí el getGames, ¿vale?
Y ya lo utilizaríamos.
En este caso, para no liar y estar mucho rato, lo que voy a hacer es tener también en videogames,
voy a hacer otra función aquí que sea function getCoverImage,
donde le vamos a pasar toda esta cosa, el attributes.cover, no sé qué, no sé cuánto.
Se lo vamos a pasar todo.
Y que sea aquí dentro donde vamos a recuperar esta información
y además vamos a crear la URL correcta.
Entonces, aquí sacaríamos esto.
Esto lo podemos sacar también de aquí, attributes, URL, así.
Y aquí debemos crear la URL correcta, que es con la API URL y la URL de la imagen.
Porque la API URL es justamente donde tenemos desplegado esto,
que puede ser que sea desplegado a producción o en localhost o donde sea.
Pero es que si no, si nos fijamos en la API, nos está dando el barra uploads.
Pero es que este barra uploads se refiere a localhost 2.1337,
no donde tenemos este que es localhost 3000.
Si aquí intentamos acceder al uploads, nos va a petar.
Así que tenemos que asegurarnos que estamos poniéndole el dominio correcto, ¿vale?
Así que ahora este getCoverImage, le pasamos el attributes,
y ya nos habrá creado la URL correcta eso, pero, ¿vale?
Vamos a ver aquí, localhost 3000.
Ah, no ha importado, no ha importado esto.
Import API.
Esto es lo que pasa cuando no utilizan linter, ¿vale?
Aún así no me sale de imagen.
Vamos a ver por qué.
¿Por qué no sale de imagen?
Pone que no existe la imagen.
¿Por qué?
Ah, porque he puesto...
Vale, vale, no pasa nada.
Esto es porque cuando hemos puesto la variable entorno,
he puesto API URL.
Vamos a poner Strapi URL, ¿vale?
Vamos a poner aquí Strapi URL,
que esto va a ser esto de aquí, Strapi URL,
y aquí vamos a poner la API URL, ¿vale?
Vamos a tenerlas separadas, que además tendría sentido
porque a lo mejor las imágenes las podemos tener en otro servidor,
puede ser Cloudinary, puede ser un millón de cosas.
Así que aquí vamos a poner la Strapi URL,
y la Strapi URL es el que vamos a utilizar aquí,
no la API URL, que sería incorrecto.
Vale, a ver ahora.
Strapi is not defined, porque lo hemos importado aquí.
Strapi URL.
Bueno, nos estamos acercando.
Nos estamos acercando, pero he puesto una barra de más.
Porque el local este, este no debería tener esta barra.
Y ya lo tenemos, ¿vale?
Ya tenemos al menos nuestras imágenes.
Ya hemos sacado toda la información de los videojuegos,
la estamos mostrando con Nexies.
Sí, el texto no está en negrita.
Eso es porque no me está devolviendo el reach.
O sea, no me lo está devolviendo de forma rica la descripción.
También es verdad que lo que nos está devolviendo es un markdown,
que eso lo podemos arreglar, ¿eh?
O sea, nos está devolviendo el markdown y por lo tanto,
mira, ¿ves?
Me está devolviendo el markdown.
Este markdown lo deberíamos transformar,
y lo podemos hacer con un React Server Component,
lo cual está bastante bien.
Hola, ¿cómo harías para adaptar los datos que llegan de una API?
Para partir de ellos, utilizarlos son componentes que utilizan esos datos.
Pero si llegado el caso, cambia una propiedad a la API,
no se tenga que cambiar en todos los lugares donde se utilizó.
Yo creo que lo ideal es tener aquí que hagas el mapping de datos
antes de retornarlos, ¿no?
Aquí tú haces un mapping de datos de forma que en el data
tú haces la transformación que haga falta.
Y aquí tú siempre, pues, estés transformando los datos como sea necesario, ¿no?
Por ejemplo, pues, para que te hagas una idea,
aquí podrías sacar el title y el description de atributos, ¿no?
Podríamos sacar también la URL de los atributos,
estos puede ser el cover, ¿no?
Y entonces ya siempre devolveríamos title, description y cover, ¿no?
Y esto lo devolveríamos aquí, return, y ya está.
Lo que estaríamos haciendo aquí es un mapping antes de devolver los datos.
Y lo harías en un solo sitio.
Al menos separado de tus componentes.
Y tus componentes no tienen por qué saber que haces esto.
De forma que esto es una caja negra.
Que si el día de mañana cambias la API, cambian el mapping de datos
y respetas el contrato de salida de este método,
todo seguirá funcionando correctamente.
De hecho, fíjate si es interesante que aquí podrías devolver un objeto plano
con lo que esperas para moquear los datos y debería funcionar todo.
Y de hecho, es una forma bastante interesante y correcta para hacer testing también.
Tiene que haber un render de, por ahí, tiene que haber algún render markdown react component.
Tiene que haber por ahí una forma de renderizar el markdown en un react server component.
React markdown server component.
Este es justamente el que había abierto.
React markdown save.
A ver si pone aquí server.
Claro, me gustaría que asegurarme react component to learn this package.
Bueno, tiene buena pinta este.
Vamos a fiarnos a ver si a este funciona, ¿vale?
Que alguien me decía que no se veía en negrita.
Vamos a ver si con este funciona.
Tenemos que transformar el markdown a HTML.
Para transformar el markdown a HTML podemos utilizar algo como esto, ¿no?
Donde aquí tendríamos, ¿ves?
El markdown y entonces lo transformamos justamente.
Explica bien por qué no usar la image de NextImage.
Lo han comentado antes.
NextImage.
Pricing.
A ver.
NextImage es un componente de Vercell que lo que hace es que automáticamente te optimiza las imágenes.
Lo cual estaba muy bien.
Pero tenéis que tener en cuenta que en el plan hobby solo tenéis mil imágenes.
Que dependiendo del caso es mucho.
Pero imágenes que sean dinámicas o que haya muchas imágenes, mil puede ser bastante poco.
Entonces no digo que lo utilicéis o que no lo utilicéis.
Lo que digo es que tengáis cuidado, ¿vale?
No se trata de usarlo.
No es blanco o negro.
Se trata de tener cuidado.
Y es lo que os estaba comentando, ¿ok?
Eso es lo que tenéis que saber.
Seguramente para vuestro portfolio que tendréis 20 imágenes no vais a tener ningún problema.
Pero si, por ejemplo, imaginad que hacéis una web como Fotocasa, por poner un ejemplo, ¿no?
Pensad que lo que tenéis aquí en Fotocasa, en esta web, es que los usuarios pueden subir imágenes.
Y cada imagen, cada inmueble tiene 25 imágenes o 60 imágenes.
Con que tengas unos cuantos usuarios y cada inmueble tenga 50 imágenes, ya te puedes imaginar, ¿vale?
Te va a salir muy caro.
Que ahí gana dinero Vercell, obviamente.
Pero lo digo para que entendáis el valor de las cosas y cómo funciona en la vida real.
Vale, venga, vamos a fiarnos.
Bueno, aquí parece que es solo real markdown.
Es que esto es lo que me gustaría.
Porque como pone esto...
Ah, bueno, pues eso es un plugin.
Vale, vale.
Pues venga, va.
Vamos a probar.
Venga, vamos a probar.
Nos ponemos aquí.
Aquí vamos a poner este...
Y en el markdown, esto...
Claro, espero que no tenga que ser en el cliente.
Vale, esto lo tendríamos aquí.
Aquí esto lo envolvemos con esto.
Y ya estaría.
Vamos a ver si esto ha funcionado.
Nos vamos por aquí.
Vale.
Ah, coño.
Esto es porque he hecho el mapping de datos aquí.
Que os he dicho que no lo tenía que grabar.
Y lo he grabado.
Y entonces, claro, por eso se me está quejando.
Vale, igualmente se me está quejando.
Vale, se está quejando justamente porque no es un componente React Server Component.
Es que este es el problema muchas veces.
Pero bueno, es un error interesante para que lo veamos, ¿vale?
Fijaos que funcionar parece que funciona todo bien, ¿no?
La página web funciona.
Fijaos que aquí se ve la negrita, ¿vale?
Todo perfecto.
No hay ningún problema.
Pero, pero hay un problema muy interesante que está ocurriendo.
Y es este de aquí.
Esperaba que el HTML del servidor tenía que contener un párrafo que fuese el mismo que el que ha visto en el cliente.
De hecho, fíjate que cuando haces, refrescas, ¿ves que hace como un salto?
Lo que está pasando, básicamente, el problema, es que lo que está renderizando en el servidor React y lo que está renderizando en el cliente no son iguales.
No encaja.
Y se nos está quejando justamente por esto.
Así que, ¿qué significa esto?
Pues lo que está significando es que este componente de React Markdown no renderiza lo mismo en servidor y en cliente.
Develop it Snarkdown.
Mira, voy a utilizar este que sé que funciona, que es súper pequeño, que sé que este hombre no me falla nunca.
Sé que no es lo ideal, lo sé, lo entiendo.
Pero en tiempos de Snarkdown.
Y ahora os explico qué es esto porque este tío es un crack.
Mira, parse, vale.
Markdown MD to HTML, ¿vale?
Y esto va a funcionar perfectamente, lo sabe Dios, lo sabe Dios porque es que no falla este hombre nunca.
No falla.
Ahora me deja fatal y sí que falla, ¿eh?
Pero vamos a verlo.
Attributes.
Ah, no, claro, esto lo teníamos que hacer aquí.
Vale, quitamos esto.
Y aquí sí le vamos a poner que confiamos en el set Dangerously, set InnerHTML.
Y aquí hacemos el HTML, ¿cómo lo hemos llamado?
MD to HTML.
¿Vale?
Esto por aquí, esto por acá.
Pam, pam.
Pam, pam, pam.
Ah, esto ya lo he cerrado aquí.
Esto por aquí.
Esto lo he importado ya.
Esto por acá.
Y en el localhost 3000, vale, me dice que no está definido.
Ah, porque esto tiene un default.
Y ahora sí, cuando quitemos la L y lo importemos, ¿vale?
Ahora sí.
¿Ves?
Cero problemas.
Sabía que iba a funcionar.
¿Qué es lo que he hecho?
Para hacerlo paso a paso y para que entendáis.
A ver, claro, me dice debe guerra.
Mido, pero también podrías hacer un graper de ese componente con la directiva useClient
y usar ese graper en su lugar.
Podría hacer eso, pero sería una mierda.
¿Por qué?
Uno, porque en realidad es contenido que es estático y ya estaríamos perdiendo el beneficio
del React Server Component.
Eso es lo que muchas veces haríamos, pero el problema es que entonces estaríamos cargando
en el cliente la transformación del markdown, que es una biblioteca muy tocha, muy grande,
que en realidad lo que tiene sentido es que se haga en el servidor porque ese contenido,
ese texto, no va a cambiar.
Yo entiendo que eso es lo que lo arregla, pero no es lo correcto.
Una cosa es que lo arregle y otra cosa es directamente hacerlo mejor.
Aquí, en este caso, lo que estamos haciendo es hacer la transformación directamente en
el servidor.
Para hacer la transformación estoy utilizando esta biblioteca que se llama Snartdown, que
es del creador de Priak.
Este tío es un crack, que es muy bueno.
Y fíjate que es una biblioteca que parsea el markdown y ocupa solo un K.
Un K.
¿No es más fácil poner un strong?
A ver, sí, pero esto no sabes si el día de mañana alguien va a poner un strong, un
strong, un deep o lo que sea.
O sea, lo que estamos haciendo es justamente controlar que si el día de mañana cambia el
contenido, pues que se haga y ya está.
Si ahora de repente en Strapi alguien nos cambia nuestro contenido, pues ahora ya estaría
arreglado.
Entonces, voy a hacer la paginación y luego vemos a ver qué me da de tiempo.
Que si no, otro día pues haremos más cosas.
La paginación está muy chula porque fijaos que en nuestra API, cuando voy a paginar
la home con un ejemplo para que entendamos cómo funciona.
Lo chulo de la paginación, cuando nosotros entramos a la API, que ya está hecha, fijaos
que aquí tenemos meta, pagination y te dice página 1, el page, página actual, page size,
número de resultados, page count, número de páginas y el total es el número de resultados
totales que hay.
O sea, cuántos resultados totales hay, ¿vale?
Y para paginar ya la API viene preparada.
Utilizamos pagination.
Y en pagination tenemos diferentes opciones.
Por ejemplo, podemos configurar el page size y decirle que el page size, o sea, el número
de resultados por página, le vamos a decir que sea 2.
¿Ves?
Ahora lo ha limitado a 2 resultados o me ha devuelto 2 videojuegos y me está diciendo,
vale, estás en la página 1, el page size, número de resultados es 2, entonces tienes
2 páginas y el total de resultados es 3.
Si le decimos que el page size sea 1, ahora me dirá que hay 3 páginas y en cada página
hay un videojuego, por lo que solo tenemos 3 videojuegos.
¿Ves?
Me dice page size 1, page count 3, total 3.
Está muy bien porque con esto ya podemos filtrar, ¿no?
Y si queremos paginar, pues igual que utilizamos pagination, podríamos poner aquí el page y decirle
que pagina, devuelveme la página 3.
Y aquí tendríamos el code of what Ragnarok, aquí nos dice estamos en la página 3, ¿vale?
Con esto vamos a poder paginar en un momentito.
Ahora, ¿qué pasa?
Que en Next.js pues tiene su truqui.
Entonces vamos a crear un componente que le vamos a llamar pagination.
Pagination.js.
Export function pagination.
Le vamos a pasar la paginación, ¿vale?
Le vamos a pasar el objeto que tenemos aquí.
Este objeto se lo vamos a pasar como prop para tener toda la información de cómo está la cosa, ¿vale?
Así que lo que le va a llegar, el pagination, va a ser esto.
Lo podríamos hacer mejor de pasarle las props separadas y tal, pero bueno, solo para que tengamos aquí.
Necesitamos el page, el page count y el total que lo sacamos de pagination, ¿vale?
Porque es lo que le vamos a pasar.
Esto aquí.
Y aquí tendríamos que saber, uno, si es la primera página.
¿Por qué?
Vamos a flow byte y vamos a utilizar, vamos a ver qué hay por aquí.
Interesante.
Mira, aquí tenemos unos cuantos componentes.
Este está muy chulo.
Este es un poco más complicado, pero no es imposible porque aquí habría que calcular las dos anteriores,
las dos posteriores del que está en el centro.
Pero es verdad que es un rollo el corner case, ¿no?
De si estás al principio o si estás al final.
Entonces vamos a utilizar al menos, mira, este al menos.
Uno de 10.
A ver, este tiene buena pinta, ¿no?
Este, por ejemplo, este tiene buena pinta.
Este pequeñito, vamos a poner este pequeñito, ¿vale?
Vamos a poner retur, vamos a poner esto por acá.
Vale.
Los comentarios los quitamos porque no les gusta.
De hecho, me gustaría aquí que se pudiera copiar con React directamente, ¿sabes?
Pero no.
No te deja.
Vamos a cambiar todos los class por class name.
Aquí vamos a poner last page cuando el page es igual al page count.
Este pagination lo vamos a renderizar por ahora aquí.
Pagination.
Vamos a ver cómo va quedando este componente.
Vale.
Y le tenemos que pasar aquí pagination, ¿vale?
¿De dónde recuperamos el pagination?
De la API.
Fíjate que en la API, el getGames.
Claro, ahora este getGames antes estaba devolviendo directamente la data.
Pero ahora necesitamos tanto data como pagination.
Así que vamos a devolver las dos cosas.
Porque fíjate que aquí en la API, en nuestra API, aquí, tenemos la data, que es los datos.
Y en meta tenemos pagination.
Vale.
Pues tenemos que recuperar meta.
O sea, aquí meta.
Tenemos data, meta.
Y pagination lo sacamos de meta.
¿Vale?
Y este pagination es el que tenemos que utilizar.
Así que ahora esto no será games exactamente.
Será data.
Que lo vamos a cambiarle el nombre a games.
Y sacamos el pagination.
Y este pagination se lo pasamos al componente paginación.
Y aquí es donde vamos a hacer nuestra magia.
Voy a mover esto un poquito mejor.
¿Vale?
Vamos a ver visualmente al menos cómo va quedando la cosa.
¿Vale?
Mira, fíjate que tenemos esto aquí.
Como tenemos esto, ahora no funciona.
No funciona nada.
Tenemos que darle funcionalidad.
Ahí.
¿Se ve?
Ah, sí, sí.
Pensaba que quedaba algo por encima.
Tenemos que darle funcionalidad.
Obviamente.
Esto todavía no funciona.
MT8.
¿Vale?
Muy bien.
Entonces, aquí nos está dando información de cuántas entries tenemos.
Si podemos ir para adelante, para atrás.
Cosas que tendríamos que hacer.
Por ejemplo.
Mira, mostrando.
Mostrando.
De videojuegos.
Mostrando tal.
De videojuegos.
Si es la primera página.
O sea, si es la primera página, significa que este botón tendría que estar desactivado.
¿Vale?
Importante.
Así que a este le vamos a poner disable.
Si es la primera página, desactivamos ese.
Y este, si es la última página.
Esto es...
Mira.
Is last page.
Esto es súper típico y esto se hace siempre.
O sea, si es la última página o la primera página, lo que hacemos son desactivar los botones.
Entonces, también vamos, podríamos desactivar también, pues, los pointers.
¿Vale?
Vamos a decirle.
Oye, si esto de aquí, esto lo vamos a tener que modificar aquí.
Pero aquí, por ejemplo.
Podríamos decir.
Oye, si es la primera página.
Si la primera página es true.
Lo que vamos a hacer es que esto sea pointer events known.
Le vamos a poner una opacidad un poquito más pequeñita.
¿Ok?
Y si no, esto lo dejamos así.
Y algo parecido a esto, lo vamos a tener que hacer aquí también.
¿Vale?
Cambiamos esto por un template string para poder hacer una interpolación aquí.
Y aquí le decimos.
Oye, si es la última página, pues, nada.
Pointer events known.
Y aquí, pues, vamos.
Ah, le ponemos opacidad 50.
Esto lo ideal sería sacarlo a un componente.
Nosotros aquí, porque lo estamos haciendo como lo estamos haciendo.
Pero importante.
Vale.
Vale.
Ahora se ve que sí que está bien.
Lo que pasa es que me he cargado un flex.
Creo que este flex.
¿Vale?
Ahora.
¿Qué pasa?
¿Por qué salen los dos desactivados?
Porque como hemos hecho que la paginación, claro, solo tengo tres resultados.
Y ahora mismo la paginación me da todos los resultados.
Por lo tanto, no podría ir ni para adelante ni para atrás.
No tiene mucho sentido.
Imaginemos que tenemos 10.000 millones de páginas.
Que no es el caso.
Pero imaginad que tenemos muchos resultados.
Aquí, aparte de todo esto, tendríamos que utilizar lo que hemos hecho aquí en la API.
Cuando hemos puesto...
Ah, vaya, que lo he perdido.
Lo que puedo hacer es aquí era paginación, page 1, page size.
Vamos a poner 1.
¿Vale?
Y este page se lo pasaremos por aquí.
Page 1.
Y esto es lo que vamos a poner aquí.
Empezamos primero con la página 1.
Y aquí en page le deberíamos pasar el page.
Por defecto, ahora mismo le vamos a decir que nos devuelve a la página 1.
Luego lo haremos correctamente para poder paginar.
Vale, aquí espérate que he petado algo aquí.
Page size.
Esto.
Ahí he puesto algo que no estaba.
Al menos ahora ya me devuelve la página 1.
Y me devuelve un solo videojuego por cada uno.
Fíjate que ahora el previews, porque estoy en la primera página, está desactivado.
Pero el siguiente sí que funciona.
Pero fíjate que si le doy, ahora mismo no pasa nada.
¿Qué es lo que deberíamos hacer?
¿Qué sería lo ideal para hacer que funcione esto y tal?
Podríamos hacerlo con una navegación o con un link.
Y lo correcto es que esto no sean botones, sino que esto sean links.
¿Vale?
Sí, lo siento porque estamos utilizando buttons.
Pero tengo que cumplir con el ejemplo.
Porque si no, luego os ponéis a poner botones por todos lados.
Pero esto no pueden ser botones, aunque visualmente parezca un botón.
¿Vale?
Esto tiene que ser anchors.
Y cada anchor tiene que tener un href.
Y el href te tiene que llevar a la siguiente paginación.
Porque esto tiene que ser, aunque se vean visualmente como botones, fíjate que se ve como un botón,
tienen que ser enlaces si va a la siguiente página o no va a la siguiente página.
Así que, bueno, de hecho este, lo que tenemos que hacer ahora es calcular cuál es la siguiente página, cuál es la otra y tal.
Por ejemplo, la siguiente página, obviamente, es página más uno.
Y la previous page va a ser página menos uno.
Sé que parece obvio, pero es que esto es lo que nos va a permitir ahora crear la URL.
Pre-page-url.
Si tenemos, joder, qué bueno es esto.
Si tenemos primera página, o sea, si es la primera página, esto va a ser null.
Y si no, vamos a añadirle este query param, ¿no?
Y lo mismo vamos a hacer con el next-page-url.
Si es la última página, pues va a ser null.
Y si no, lo que hacemos es crear la URL con el page igual y la siguiente página.
Y ahora esto lo podemos utilizar aquí en el href, ¿vale?
Tanto la página anterior como la siguiente página.
Ahora, vale, vale, string object but got null.
Pues no null, in the find, ¿vale?
Que no le gusta el null, con razón.
Ah, pensaba que en el href este se lo iba a poder tragar.
A ver, no me gusta esto.
No es lo suyo, pero bueno, no pasa nada.
Así se lo comerá con patatas.
Si no, lo que podemos hacer realmente es ponerle la barra.
Porque, a ver, cualquiera de las dos no pasa nada porque va a estar desactivado y no debería pasar nada.
Pero igual entonces lo que tendríamos que hacer es cambiar que no sea un enlace.
Cuando no tiene href y no tiene paginación, lo ideal sería quitar el link y hacer que sea un span, por ejemplo.
O un div, en este caso.
Pero bueno, al menos ya tenemos el enlace.
Y fíjate que ahora, cuando le he dado al next, sí que ha cambiado esto, pero no ha cambiado el contenido.
¿Por qué no ha cambiado el contenido?
Porque necesitamos leer la query param.
Y esto es mucho más sencillo de lo que parece.
Porque aquí en la home, en el componente, podríamos acceder a search params.
Y en search params podríamos acceder a justamente la página.
El search params es esta parte de aquí, ¿no?
Que serían los query params.
Aunque el nombre correcto es search params.
Y tendríamos acceso a ese dos que tenemos por aquí.
Así que le vamos a pasar esto, creo.
Vamos a poner un console log aquí del page.
Vamos a hacerlo del search params.
Lo tenemos aquí del console log.
Vamos a verlo aquí.
¿Vale?
¿Ves que lo tenemos aquí como un string?
Obviamente aquí tenemos que hacer validaciones para asegurarnos que la cadena de texto es un número y todo esto.
Que no sea none y tal.
Pero lo podemos transformar aquí con el page.
Ya le pasaríamos la paginación.
¿Vale?
Y ahora ya podríamos ir navegando.
Nos vamos al next, next.
Y fíjate que cargando súper rápido, que casi no se ve, tendríamos que cambiar aquí la paginación también.
Esto sería el total, ¿no?
Si no me equivoco.
Este sería el total.
Y aquí deberíamos tener uno de, para hacer la paginación, a ver, tendríamos el page size por page size por el page, ¿no?
O sea, tendríamos que...
Bueno, da igual.
No importa.
Ya lo hacéis vosotros.
Mostrando uno de diez, que no es así.
Uno de diez de tres videojuegos.
Pero fijaos que ya tendríamos la paginación.
Esta sería la página uno.
Como es la primera página, no tenemos página anterior.
La página dos, que aquí sí que podemos ir para adelante y para atrás.
Y en la página siguiente, que tendríamos el God of War Ragnarok, que es el último.
Y ya no podríamos continuar para adelante.
Pero fijaos que en un momento hemos hecho una paginación, que está súper bien.
Y ya está.
La página dos, que no tenemos uno.
La página dos, que es la página dos.
Y ya está.