logo

midulive


Transcribed podcasts: 605
Time transcribed: 13d 3h 7m 36s

This graph shows how many times the word ______ has been mentioned throughout the history of the program.

Amigos y amigas, vamos a desarrollar desde cero un Twitter, un X, llámale como quieras.
Desde aquí, igual hoy podemos resucitar a Twitter, podemos resucitar a Twitter, ¿vale?
Entonces, lo que vamos a hacer es intentar, poco a poco, de forma incremental,
nos vamos a ir acercando a este Twitter.
Obviamente, este Twitter es una cosa seria, no lo voy a hacer en 40 minutos,
no vamos a engañar a nadie, pero sí que lo que vamos a hacer es,
poco a poco, ir incrementando lo que vamos haciendo,
lo vamos a hacer 100% de código abierto, de hecho, vamos a empezar por ahí,
creando el repositorio, para que no se diga,
y así, pues, me obligaré a ir comiteando, porque si no, no lo hago.
Clone de, o Twitter, Twitter clone, ¿vale?
Y vamos a poner que esto sea público, creamos el repositorio,
y así ya empezaremos a tenerlo aquí, y así, pues, de vez en cuando podréis ir participando también, ¿vale?
Lo que vamos a hacer es utilizar Supabase.
Si no sabéis qué es Supabase, Supabase es la leche, es la leche.
Me encanta que todavía en el título pone The Open Source Firebase Alternative.
Yo le recomendaría cambiarlo, porque ya, ya toca.
Ya tiene como su propia entidad, yo no recomendaría que sigan atándose a Firebase,
pero bueno, ahí siguen, ¿no?
Supabase is an open source Firebase Alternative.
Es verdad, totalmente cierto, porque Supabase es 100% de código abierto.
En realidad lo podríais hospedar vosotros mismos y os saldría gratis, entre comillas.
Pero lo cierto es que Supabase es que al final, pues, es como una plataforma que te da una base de datos
súper sencilla a utilizar con tiempo real, autentificación, APIs, Edge Functions,
o sea, funciones en la nube, suscripciones de tiempo real, storage, vectores, para machine learning,
inteligencia artificial y todo esto, ¿no?
Bueno, pues tiene un montón de cosas y el precio, amigos, tienes 0 dólares y el único problemita que tiene
es que está limitado a dos proyectos gratuitos.
O sea, en este caso yo creo que tiene mejor free tier Firebase, ¿vale?
¿Ves? Límites amplios para empezar.
La verdad es que Firebase está bastante bien en que puedes tener 10.000 millones de proyectos y tal.
Pero luego, si vas mirando un poco, se parecen mucho, son bastante similares.
Por ejemplo, pues un giga de datos almacenados, aquí tienes transferencia y aquí también tienes, ¿lo ves?
Dos gigas, son bastante similares.
Firebase puede ser mejor en algunas cosas, pero creo que en general te puede convencer más Supabase
si no fuese por los dos proyectos limitados, ¿eh?
Más o menos, o sea, yo no lo haría por el free tier, sino en realidad por cómo puede escalar el proyecto, ¿eh?
No os diría tanto de por el free tier, sino pensad en lo que hay que pagar después.
Porque si no, el free tier es un poco tramposo, porque os puede engañar, así que mejor lo otro.
Y que yo recuerde, no pide tarjeta de crédito, ¿eh?
Que yo recuerde, no pide tarjeta de crédito, porque básicamente te pausa los proyectos, lo cual no está mal.
¿Ves? Los proyectos gratuitos son pausados después de una semana de inactividad, pues también tiene un poquito de problema.
Y además, ya te digo que si te pasas, te cortan rápido, ¿eh?
Así que no necesitas tarjeta de crédito.
Ya hemos visto algunos de los servicios que tienen, que tienen un montón.
Os podéis ir a Start Your Project.
Yo tengo unos cuantos proyectos, para que veáis, ¿eh?
Y vamos a crear uno nuevo, aquí en la organización de Clean Codes, no sé qué, no sé cuánto.
Y vamos a ponerle Depter.
Venga, vamos a llamarle Depter, que os gustó el nombre, ¿eh?
Y vamos a ponerle un password.
El password no os lo voy a enseñar, ¿vale?
Porque si no, tenéis más peligro que una caja de bombas.
Así que vamos a poner una región, la que esté más cerca de mí.
Bueno, voy a poner Frankfurt, aunque luego casi todos los que tenemos aquí, mucha gente es de Latinoamérica.
Y el pricing plan le ponemos cero.
Así que nada, creamos un nuevo proyecto.
Create new project.
Y esto ahora tarda unos segundos en crear el proyectito.
Y veis que pone Retrieving API Keys, Setting Up Project.
Esto tarda unos segundos, ¿vale?
Así que mientras esto se lo está pensando.
NPX Create Next App.
Vamos a crear nuestra aplicación con Next.js.
Decimos que sí.
¿Cómo se va a llamar esto?
Venga, Depter.
¿Vamos a utilizar TypeScript?
Sí, pero no te preocupes, ¿eh?
Si no tienes ni puñete la idea, porque facilito, facilito.
¿Vamos a utilizar Slint?
Sí.
¿Vamos a utilizar Tailwind?
También.
Y Source Directory.
A mí me gusta que esté todo el código fuente en la carpeta Source.
Pero aquí cada uno que haga lo que dé de la gana.
AppRouter.
¿Recomendado?
Pues me lo recomiendas.
¡Pá adentro!
In por alias.
¿Quieres personalizarlo?
No personalizamos.
Y ya se pone a instalar.
Me da mucha rabia porque utiliza MPM.
¿Por qué utiliza MPM por defecto si luego esto...
¿Qué está pesando?
¿Qué está pesando Vercel?
Desde aquí.
Desde aquí, amigo Vercel.
Tío, no puede ser que tengas toda la documentación ahora con PNPM por arriba o por abajo,
no sé qué, no sé cuánto.
Bueno, si no, sabéis de qué estoy hablando.
En Vercel, ahora, si yo qué sé, vais a Install NextGIS, pues casi todo lo pone con PNPM.
No sé si habrán cambiado, estarán arrepentidos.
Pero, ¿veis?
PNPM es la primera opción.
Entonces, no sé, me gustaría que...
Me imagino que es porque utiliza MPM, pero igualmente hay muchos que aunque utilices MPM,
te utiliza o te pregunta, al menos que te pregunte.
Yo creo que lo mejor sería preguntar.
Oye, ¿queréis hacer la instalación con MPM o con PNPM o con qué?
Voy a hacer el Install con PNPM, más que nada, para que se cargue todos los new modules.
Lo siento porque he hecho el MPM Install, pero lo voy a volver a hacer, es un momento.
Pero es que me da un poco de rabia.
Vale, pues ya está.
Y en PNPM RAM Depth, entonces, vamos a abrir el proyectito en nuestro editor de código favorito,
que es Visual Studio Code, y vamos a ver un poco por encima.
Ya sabéis, tenemos la carpeta Source, con la carpeta App, con su Fabicon,
unos estilos por defecto que nos vamos a cargar inmediatamente,
un fichero Layout que sería lo que envuelve nuestra aplicación.
El Layout, pues como la plantilla.
Y aquí en Children, sería lo que se está renderizando, aquí en Page.
Que ya veis que aquí hay un montón de cosas, todo con Tailwind.
Vamos a poner Hola Twitter, ¿vale?
Lo ponemos aquí, vamos a borrar este image, borramos esto.
Y ahora, si entramos aquí, pues ya tenemos Hola Twitter,
y así, pues ya lo tenemos más limpio todo.
Lo importante es que ya se ha inicializado.
También nuestro querido Superbase.
Perfecto.
Vamos a empezar con la base de datos, si os parece.
Fijaos, os enseño, por si no habéis utilizado nunca Superbase,
aunque mucha gente seguro que lo ha utilizado.
Superbase, lo hemos comentado antes, es una plataforma con un montón de servicios
para tener base de datos, autentificación, storage, un montón de cosas.
Tiene librerías para JavaScript, Flutter, Python, C Sharp, Swift, Kotlin y tal.
Tienes un montón de proyectos de ejemplo.
Y aquí a la izquierda, tenéis como diferentes cositas, ¿ves?
El Table Editor.
Tenéis SQL Editor.
Esto, por si sois muy cracks, pues directamente podéis editar con SQL directamente.
Base de datos, autentificación, esto lo veremos después.
Lo de base de datos y autentificación lo tocaremos después.
Storage, que esto también nos vendrá bien porque más adelante
podríamos permitir a los usuarios que suban archivos.
Entonces los tendremos que poner en Storage.
Edge Functions, Reportes, Logs, ApiDocs y Project Settings.
Por ahora vamos a empezar por el principio, ¿vale?
Y ya os digo que lo vamos a intentar hacer de forma muy iterativa.
Que por cierto, que por cierto, porque si no luego la gente se me pone...
Me he basado, porque me ha gustado mucho, en un curso, lo que vamos a ver hoy,
me he basado en un curso, sí, en un curso que es gratuito, por si no os gusta como yo lo hago,
por si lo que sea, que hicieron aquí.
¿Ves?
Build a Twitter Clone with the Next.js App Router and Superbase, de John Mayers.
Está súper chulo.
O sea, no os quiero engañar y decir, no, esto no.
La verdad es que me lo vi hace unas semanas.
Está súper genial.
Está en inglés, obviamente, os lo recomiendo, porque es totalmente gratis
y a lo mejor os sirve para revisarlo o lo que sea, ¿no?
Pero bueno, obviamente yo os comentaré más cosillas y os iré comentando y todo esto, ¿vale?
Table Editor.
Bueno, el Table Editor, pues nada, vamos a empezar por el principio.
Lo más básico que necesitamos para Adepter, le vamos a llamar Post, ¿no?
Porque necesitamos Post de los usuarios.
Post que crean los usuarios para compartir información, la nata de nuestra aplicación, ¿vale?
Muy bien.
Primera cosita, esto de Enable Road Level Security.
Esto es súper importante.
Esto es básico y esto es toca pelotas, ¿vale?
Básicamente el Road Level Security es como restringimos el acceso a los datos,
a la actualización de los datos, borrar los datos y todo esto.
Y le tenemos que decir qué usuarios tienen acceso y tal.
O sea, que hoy justamente veremos si usuarios autentificados o no
tienen acceso de lectura y de escritura y todo este tipo de cosas.
Porque es que si no, no puedes, básicamente no puedes acceder a los datos.
Así que ya veis que ponemos Enable, ¿vale?
Road Level Security.
Lo veremos después para poder ver los datos, ¿vale?
Y fíjate que dice, las políticas son requeridas para poder acceder a los datos.
Necesitas escribir un Access Policy antes de que puedas hacer una query a los datos para esta tabla.
Así que eso.
Dice, sin una política, hacer un query a esta tabla va a resultar en un array vacío.
Así que ya empezáis por aquí, ¿vale?
Campos, luego lo arreglamos, pero por ahora los campos más seguros que necesitamos.
Un ID, pero en lugar de un integer 8 vamos a utilizar un UUID, ¿vale?
Que esta va a ser la llave primaria.
O sea, este es el identificador único y repetible con el que nos vamos e inmutable, ¿vale?
Si hiciste el curso de SQL lo deberías saber.
Created at, esto es un campo que se hace automáticamente y que ya tiene el tipo que es timestamp
y un valor por defecto que es now.
La ID también tiene un valor por defecto y esto que veis aquí son funciones que ya existen en PostgreSQL.
Una te genera un identificador único random, el otro te crea el timestamp, ¿vale?
O sea, está muy bien porque tienes un montón de expresiones o funciones que ya existen, ¿veis?
Y hay como sugerencias que le podéis dar aquí y os las hacen.
En este caso nos quedamos con estas dos y vamos a añadir una columna que obviamente va a ser la más importante
que es el contenido, porque sin contenido el contenido es el rey.
Luego más adelante añadiremos más, ¿eh? O sea, que no os preocupéis.
Ahora, un valor por defecto, le dejamos aquí este, pero le vamos a poner que no pueda ser nulo.
Fijaos aquí en esta ruedecita que podéis hacer como más cositas, le decís que no pueda ser nulo.
¿Por qué? Porque si no podría, si los usuarios creando tweets vacíos no tendrían sentido.
Venga, le damos a Save, ¿vale? Añadiendo las tres columnas para el post y vamos a crear unos tweets de ejemplo.
Venga, vamos a crear aquí esto. Esto como por defecto se genera, los dejamos y aquí, hola, Depter, ¿vale?
Ponemos esto, venga, ponemos otro, Insert Row. Fijaos aquí que pone Insert Row, Insert Column.
Esto es importante. Insert Row es que vas a insertar un elemento en la tabla post.
Insert Column es que vas a añadir otra información nueva, o sea, una columna nueva como por ejemplo el User ID que lo vamos a hacer después.
Por ahora empezamos con esto, ¿vale? Y luego vamos a poner el Insert Row otra vez.
Otra vez nos ponemos con esto, ¿vale? Muy bien, ya tenemos tres tweets.
Ya a ver si... Muy bien. Ahora, hemos creado ya el proyecto de Next.js, ya tenemos sí a todo.
Vamos a poner el linter, ¿vale? Vamos a poner un linter porque no me gusta nada trabajar sin linter porque luego la liamos pardas.
Yo voy a añadir un linter que deberíais hacer siempre.
Como utilizo TypeScript, voy a utilizar npxs init para que me lo haga todo.
Me vaya preguntando cositas, ¿vale?
Dice, para chequear solo la sintaxis, encontrar problemas...
To check syntax, encontrar problemas y obligarte a un estilo de código.
Vamos a utilizar que utilizamos import y export y vamos a decir que utilizamos React y si utilizamos TypeScript y utilizamos tanto browser como node.
Utilizamos uno popular que, en mi caso, va a ser estándar y el formato... A mí me gusta que sea JSON, así que ya está.
Con esto tenemos. ¿Te gustaría instalarlos? Sí, me gustaría instalarlos si quiero...
¿Ves? Aquí te pregunta. Esto es lo que espero en la vida, que me hagan preguntas.
Quiero PNPM, gracias por preguntar, te lo agradezco, hombre.
Y con esto ahora, vale, pues ya tendríamos aquí unas cuantas cositas.
Vamos a ver cómo me ha dejado mi package JSON.
Aquí, este JSON.
Podríamos añadir... Vale, se lo ha petado el de Next. Me parece fantástico.
Yo lo voy a añadir... Tengo por aquí unas reglas que me gusta desactivar, ¿vale?
¿Veis aquí que pone reglas? Yo lo voy a desactivar estas por defecto.
Uno, no las uso y dos, me molestan bastante.
Sobre todo esta de React PropTypes y React in JS Scopes no tiene mucho sentido.
Y dicho esto, a ver... Vale, no me lo ha pillado.
Vamos a hacer un reload del Windows.
Ah, vale, no me lo ha pillado porque seguramente... Mira, os voy a enseñar un truco mágico.
Para el tema del linter, ¿vale?
Porque hay muchas veces que seguro que decís...
No me funciona el linter y no sé qué es.
Qué rabia que no me funciona y qué asco.
Y está bien, ¿no?
Pues fíjate.
¿Veis aquí que hay este botoncito?
Sí, y aquí hay una X.
Esto, si lo ponéis encima, veis que me está saliendo Slim con una X aquí bien fuerte.
Pues le dais aquí Open Slim Output.
Y aquí tenéis todos los errores que tenéis de Slim porque no funciona muchas veces.
Y será que hay falta una configuración y tal.
En este caso yo sé cuál es el problema, que es este de aquí.
¿Ves? Error.
Lo mejor que podéis hacer aquí es buscar error.
Entonces buscáis todos los errores, no sé qué, no sé cuánto, hasta que veáis uno que es el que tiene pinta.
Que es este.
Error while loading, no sé qué.
Tienes una regla que requiere que esté generado parser services.
O sea, que tenéis que decirle dónde está el tsconfig.
Nos vamos aquí y tenemos que poner el project.
Y aquí, si no me equivoco, es directamente así, ¿vale?
tsconfig, joder, config.json, vale, tototó.
Y ya con esto, ahora sí que lo deberíamos tener.
De hecho, ¿veis? Ahora ya sí que funciona.
Muy bien, pues perfecto.
Ya tenemos el inter.
¿Veis?
Pues veis que ya me salen errores.
Y si le doy a guardar, ya se me formatea automáticamente.
Voy a quitar la fuente esta de inter, ¿vale?
Vamos a poner aquí el clon de Twitter generado moviendo las manitas, ¿vale?
Quitamos este inter, que no me gusta esa fuente.
Ha tomado por saco.
Y ya está.
Muy bien, pues ya tenemos también el inter.
Perfecto.
Vamos con la conexión a Superbase, ¿vale?
Vamos a empezar a mostrar al menos los tweets.
Os cuento una cosa.
A ver, para conectar vuestra aplicación de NXIS con Superbase, existen...
Existen...
Por desgracia, han existido muchas formas a lo largo del tiempo.
Demasiadas formas.
Pero, por suerte, esta vez parece que es la buena.
Esta vez parece que es la buena.
Durante mucho tiempo ha habido diferentes formas.
Si estás utilizando NXIS con el app router y, además, Superbase,
la buena es esta de aquí, que es la de Auth, Auth Helpers.
Esta.
Vais a ver cómo se instala.
Bueno, esto es para crearlo ya tal.
Bueno, aquí tenéis todos los pasos.
Esta.
Esta es la buena.
Superbase, Auth Helpers, NXIS.
¿Vale?
Esta es la buena.
Esta es la buena.
Es que hay un montón de bibliotecas para hacer esto.
Es un poco rollo.
Esta es la buena y la verdad es que este artículo tiene casi todas las cosas que vais a necesitar.
Así que os recomiendo mucho que este artículo, si vais a utilizar Superbase con NXIS,
además, que tienen un montón de ejemplos de vídeo, os lo recomiendo un montón.
Vamos a hacer el install.
Venga.
El install de este paquetito.
PNPM install.
De Superbase, Auth Helpers, NXIS.
Y también de este de aquí, que si no me equivoco, es como una pierdependencia.
Instalamos estas dos dependencias para tener justamente la conexión con nuestra base de datos.
Vais a ver lo fácil que se hace, ¿vale?
Venga, ya tenemos la instalación.
¿Qué tenemos que hacer para conectar con nuestra base de datos de Superbase?
Creamos nuestro archivo .env.
En nuestro caso, vamos a poner .env.local, porque queremos que funcionen estas variables de entorno de manera local.
También puedes tener variables de entorno que sean de modo desarrollo, producción, un montón de cosas.
Utilizamos nextpublic y aquí vamos a tener que pasarle dos cositas, ¿no?
La URL y el anon key.
Anon key que no es la llave del ano, ¿vale?
No es la llave del ano que ya te estoy viendo riéndote ahora mismo.
Seguro que alguno estaba comiendo y ha echado la comida de la boca.
No es la llave del ano, sino que es la llave anónima, ¿ok?
No es la llave anónima.
Entonces, te vas a Project Settings, tampoco, ¿dónde?
Aquí, en API, ¿vale?
Te vas a Settings, aquí a API, ¿ok?
Y buscas la URL que tienes por aquí.
Esta sería la URL, así que la URL la ponemos aquí.
Y la llave de tu ano la tienes aquí, en el Anon Public.
Esta es la llave.
Y ahora alguien me dirá, hostia, pero esta llave, tío, se te ha colado, se te ha colado.
No pasa nada.
Esta llave, en principio, no debería haber ningún problema.
De hecho, lo pone por aquí, ¿eh?
La llave es segura de utilizar el navegador si tienes, claro,
si tienes activado correctamente los Role Level Security,
que esto lo veremos después.
Y para tus tablas y configuradas las políticas.
¿Por qué?
Porque esta llave no tiene derechos de administrador.
Va a estar controlando si el usuario tiene o no tiene directamente,
realmente, acceso, ¿vale?
Entonces, esta llave es normal que la podáis ver.
No os preocupéis.
No es que ahora tenéis ya la llave de Miano.
Así que no os preocupéis.
Esta, esta es la que es chunga.
¿Por qué?
Porque esta, la de Server Role, esta sí que es la que se salta cualquier tipo de control,
de chequeo y tal.
Así que esta que tiene aquí asteriscos, esta es la que no se puede ver.
Con esto ya tendríamos la conexión.
Hemos hecho el env.local.
Hemos instalado la dependencia.
Venga, vámonos a nuestra página TSX y vamos a ver si somos capaces de crear nuestra primera conexión.
Vamos a importar el create client.
No sé por qué no me sale el auto.
Create server.
Ah, mira, voy a hacer otra cosa.
From, vamos a hacerlo al revés.
Porque si no, me va a costar helpers.
Es que, ¿por qué no me sale?
¿Por qué no me sale el autocompletado?
Bueno, a ver.
Create ahora.
Create server.
Ves que hay un montón.
Create client component.
Create server action component.
Create server common client.
O sea, es un rollo.
No me gustan nada los nombres.
Pero en este caso tenemos que utilizar el create server component client, ¿vale?
Porque estamos creando un cliente de Superbase en un componente de servidor, ¿ok?
Es muy raro el nombre.
No me gusta.
La verdad es que no me gusta esto de que todos tengan el client porque queda muy raro.
Sobre todo que hay uno que se llama create client component client.
Que tienes que entender que queremos crear un cliente de Superbase, una conexión de Superbase,
desde un componente de tipo servidor, ¿vale?
O sea, que aunque eso lo tengas claro, pues ya está.
Vamos a importar las cookies desde next headers, ¿vale?
Y ya tenemos las cookies.
Esto es lo más importante que tenemos que hacer.
Las dos dependencias.
Por un lado las cookies y tal.
Y alguien dirá, ¿pero cómo que estás cargando las cookies?
¿Pero esto qué es?
Bueno, a ver.
Es que el tema es que esto es un componente que se está ejecutando, renderizando en el servidor.
Esto es nuevo del app router de NextDS.
Y esto lo que nos permite es acceder a las requests, a las cookies, a un montón de información.
Así que por eso, como estamos desde el servidor, necesitamos las cookies para que realmente Superbase sepa si el usuario está logado,
si tiene sesión, si no tiene sesión.
Y así es como creamos aquí Superbase.
Vamos a crear create server component client y le vamos a pasar las cookies, ¿vale?
Pasamos aquí las cookies y ya está.
Ya con Superbase ya podemos empezar datos.
Lo vamos a renombrar a post y Superbase from post.
Seleccionamos todos los campos, ¿vale?
Y esto, importante, es asíncrono.
Porque obviamente esto nos devuelve a la promesa.
Y si esto es asíncrono, ¿qué significa?
Pues que necesitamos así una sincronía en la función.
Tengo que hacer la función asíncrona.
Los componentes de React Server Components, o sea, los componentes del servidor de React,
pueden ser asíncronos.
Y por eso funciona esta magia, ¿eh?
No es que sea nada raro ni nada, ¿vale?
Así que, bueno, por ahora vamos a hacer el truquillo este del stringify, ¿vale?
Ponemos los post.
Vamos a ver si vemos algo.
Vale, el select lo he puesto bien.
Bueno, esto, si no me equivoco, es opcional, ¿eh?
O sea, no es obligatorio ahora mismo ponerlo.
Vamos a ver si de aquí en clon de Twitter...
Vale, ¿veis que tenemos un array vacío?
Muy bien, tenemos un array vacío.
Es normal que tengamos un array vacío por justamente lo que nos decía antes Supabase.
Como todavía no le hemos dicho ningún tipo de permiso a estos post, ¿qué pasa?
Pues que por defecto nos pone un array vacío porque es como que el usuario no tiene como
acceso a esta información.
Así que nos vamos a autenticación y fijaos aquí en configuración tenemos policías.
Policías, la policía me está atusionando.
Tenemos policías, ¿vale?
Bueno, tenemos policías, no, políticas.
Policies, policies son políticas.
Y en las políticas lo que vamos a tener que decir es cómo se tiene acceso a esta
base de datos que hemos creado, ¿no?
Aquí fíjate que nos dice que no tenemos políticas creadas, que el RLS está activado.
El RLS significa, ¿cómo era?
Eso, Road Level Security.
Joder, se me había ido.
Road Level Security.
Que es básicamente la seguridad a nivel de fila.
Vamos a ver cómo tiene acceso a la hora de leer.
Gracias, ahora me lo dice.
No es el DRS de la Fórmula 1.
Ahora, cuando añadimos una nueva política en este botón, fijaos que nos dice que podemos
empezar rápido.
Y esto sería como medio, como un tutorial en el que dices, para añadir acceso a todo
el mundo, te lo pone así.
Para insertar acceso, para no sé qué.
Pero la verdad es un poco raro.
O sea, son como plantillas ya por defecto, bastante típicas para chequear si tiene acceso
o no tiene acceso.
Esta va a ser la que vamos a necesitar ahora.
Pero os voy a decir una cosa.
Yo creo que es más fácil utilizar la de abajo.
La de For Full Customization.
Sé que es raro porque muchas veces es al revés.
Pero aquí se entiende mucho mejor.
Ya verás.
Porque aquí le das y le tienes que poner un nombre.
Que aquí sería Allow All Users to Access o to Read Post.
¿Vale?
¿Qué operación le estás permitiendo?
Pues Select.
¿Cuáles son los roles?
Bueno, pues aquí tienes diferentes roles, ¿vale?
Pero fíjate que pone por defecto serían todos los roles si no seleccionan ninguno.
Que sería mi caso, ¿no?
Y aquí la expresión que se tiene que evaluar para ver si realmente tiene o no tiene acceso
a esto.
Por lo tanto, si es una expresión, pues aquí le decimos True.
Como, pues sí, que tiene acceso True.
O sea, no tenemos que hacer ningún tipo de condición de si la ID del usuario es igual
a la ID de no sé qué.
Eso lo veremos a mejor más adelante.
Por ejemplo, ¿para qué es interesante esto?
Pues si tú tienes un tuit que has creado tú, no va a tener acceso a editarlo cualquier
usuario.
Entonces aquí le diremos, para que os hagas una idea.
El post al user ID tiene que ser igual al out punto...
Creo que era así.
No, o sea, si el usuario, la ID del usuario de la persona que está intentando actualizar
el post es igual a la ID del usuario de ese post, ¿entendéis?
Porque si no, cualquiera podría editarlo.
Aquí lo puedes complicar todo lo que quieras y más.
Pero en este caso, como ahora mismo de lectura, luego lo veremos más adelante.
Pero por ahora, solo de lectura, le ponemos el True.
Lo vamos a revisar.
Y esto, nosotros lo hemos hecho de la forma fácil.
Pero esto sería como lo hace por debajo.
O sea, en realidad, claro, pensad que Supabe se está utilizando PostgreSQL.
Y por debajo lo que tenemos es esto.
Es realmente SQL para crear la política con los permisos y todo.
Para que lo sepáis.
Una vez que lo habéis visto, le decís Save Policy y ya está.
Ya tenemos nuestra política.
Nos vamos al club de Twitter, refrescamos, ¡tachán!
Y ya vemos los tweets.
Pues esto es el inicio de todo.
Vamos a continuar.
Estaría bien que los usuarios puedan iniciar sesión.
Y que así, pues entonces, cuando el usuario haya iniciado sesión, pueda guardar un tweet y bla, bla, bla.
Vamos a iniciar sesión con GitHub, ¿vale?
¿Por qué?
Porque es el más rápido, el que da menos problemas y no hay que pagar nada.
Entonces, por esas tres, vamos a utilizar justamente esta.
Para crearte los toques, el client ID y todo esto, te vas a GitHub, a las Settings, Developer Settings.
Y aquí tienes la oportunidad de crear OAuth Apps, ¿vale?
Aquí vamos a crear una nueva OAuth App.
Vamos a poner Depter.
Por ahora ponemos que Localhost 3000.
Mi Twitter Killer.
Y aquí ya nos pregunta, Authorization Callback URL.
Esta es la URL a la que cuando tú le des a iniciar sesión en GitHub, irá a enviar la información del token.
Y entonces manejará este token y creará la sesión.
Y esta URL no la tenemos nosotros, sino que la tiene Superbase, ¿vale?
Entonces, aquí en Superbase, igual que tendríamos aquí en Authentication, nos vamos aquí a Providers.
Y fíjate, y esto es una de las maravillas que tiene Superbase.
Que tiene un montón de Providers, pero un montón de Providers.
Bueno, pues estos Providers son todas las plataformas con las que puedes iniciar sesión.
Son un montón.
Por supuesto, puedes utilizar el email, aunque el email es un poco ñe, así que lo vamos a desactivar.
Vamos a guardar este cambio, ¿vale?
Hay un botón ahí de guardar, ¿vale?
Fíjate que puede ser por teléfono, con Apple, con cuenta de Apple.
Puede ser con Discord, Facebook, GitHub, GitLab, Google, todas las que quieras y más.
Y en todas y en cada una, pues vas a ver que vas a necesitar pasarle los tokens y todo esto.
Algo parecido a lo que estamos haciendo con la de GitHub.
En GitHub vamos a activarla.
Y aquí ya me pregunta ClientID y ClientSecret.
Esto lo vamos a tener ahora cuando utilicemos esta URL.
Así que nos vamos aquí.
Ponemos aquí esta URL.
No activamos esto.
Register Application.
Y ahora nos da el ClientID, que este ClientID lo tenemos que traer aquí.
Y también el ClientSecret, que el ClientSecret, cuando le doy aquí, aparece.
Pero que estás esperando a ver si lo ves, que te esperes, que no.
No tenéis que compartir el secret, ¿vale?
El secret, sí que es verdad, este secret tiene que ser totalmente privado, ¿vale?
Así que cuidado, cuidado con esto.
Lo bueno es que si por lo que sea se te escapa, no pasa nada.
Lo puedes borrar y volver a generar, aunque es un poco rollo.
Y esto que estoy viendo el móvil es porque me está pidiendo el código de autentificación.
En fin.
¡Ay!
¿Ves?
Se me ha colado.
Se me ha colado.
Lo he enseñado, ¿ves?
O sea, he hecho exactamente lo que os he dicho que no tenéis que hacer.
Lo he hecho yo.
Ahora ya está arreglado.
Ahora cuando ya refresquemos, ¿veis?
Está aquí esta información.
He añadido dos porque le he dado dos veces al botón.
No os preocupéis.
Lo importante es que ya he añadido este token en el otro sitio, ¿vale?
Y ya me dice aquí guardar.
Perfecto.
Y fijaos, ya tenemos todos los providers y el de GitHub está aquí activado.
Así que ya tenemos esto.
Volvemos a nuestro editor y vamos a crear una forma de añadir sesión.
Vamos a crear un botón.
Vamos a crear components.
Vamos a crear auth button.tsx.
Y aquí vamos a crear un cliente.
Create client.
Component client con Superbase, ¿vale?
Tiene que ser el cliente.
Y esto va a ser un componente que se va a ejecutar en el cliente.
Así que hay que utilizar esta cadena de texto useClient.
Esto, en realidad, esto es que por defecto, si no lo pones,
todos los componentes son de servidor.
Y lo necesitamos porque si un botón es clicable,
significa que se tiene que renderizar en el cliente.
No puede renderizarse en el servidor si quieres que el usuario
de alguna forma interactúe con ello.
Ya tendríamos esto, el createClient.
Así que vamos a crear primero el Superbase con el createClient component client.
Este, ya teníamos el Superbase.
Luego esto lo podríamos sacar, ¿eh?
Vamos a poner el handle SyncIn, ¿vale?
Cuando hagamos el SyncIn, ¿qué hacemos?
Pues hacemos una wait de Supabase.auth.syncIn.
SyncIn.
SyncIn.
With OTP.
A ver.
SyncIn with...
Ah, este, con auth, que no lo veía.
Tendríamos el provider.
Y aquí le decimos cuál es el provider.
Fijaos que cuando lo pone, ya te dice a todos los que tenemos disponibles.
El que queremos es el de GitHub.
Vamos a poner aquí unas options porque le tenemos que pasar la información,
le tenemos que decir hacia dónde tiene que redirigir, ¿vale?
Y le vamos a decir ahora que redirija localhost3000.auth.callback.
¿Por qué tenemos que hacer esto?
¿Por qué tenemos que hacer esto?
Bueno, a ver.
Cuando haya iniciado sesión el usuario,
lo que va a hacer esto es devolvernos como las credenciales del usuario
para que tenga una sesión, el token que podemos utilizar.
Y esto nosotros, en nuestra aplicación,
vamos a tener que guardarlo en algún sitio.
Y obviamente lo vamos a querer guardar en la cookie.
Así que necesitamos enviar esta información.
Y esto va a ser una URL nuestra que vamos a crear ahora
para que llamemos a un pequeño método
que guarde la información esta en una cookie.
Por ahora, tendríamos esto.
Redireccionamos al auth callback.
Esto para el syncing.
Vamos a hacer ya el del sign out, ¿vale?
Sync, log out, sync out, sync out, vale.
Async, ta, ta, ta, await, supabase.
El sync out es un poco más fácil porque es out, sync out y ya está.
Entonces, estos serían los dos botones.
Vamos a renderizarlos.
Vamos a poner aquí header, button, onclick, onclick,
handle sync in y handle sync out.
A ver, para hacer el sync in un poquito más bonito,
vamos a utilizar ya flow byte, css buttons,
porque si no es un poco feo.
Y si no me equivoco, esta gente aquí, como utilizamos Tailwind,
esto es las cosas buenas de hacer las cosas rápidas así.
¿Ves que tengo aquí el syncing with wehap?
Maravilloso.
Pues vamos a utilizar este, este botón.
Este botón lo vamos a poner aquí.
¡Pam!
¡Hala!
A saco.
A saco, a saco.
Y vamos a poner aquí que al hacer onclick,
hacemos el handle sync in y al menos el sync in que sea bonito, ¿no?
No sé si habrá aquí un logout o algo.
Tu, tu, tu, tu, tu.
Logout.
Logout.
No.
Sync out.
No.
Era por si había uno que fuera igual de bonito,
pero con sync out.
Bueno.
Obviamente, los componentes, esto, icons, tss.
O sea, lo que es SVG, este SVG lo deberíamos sacar de aquí, ¿vale?
Vamos a tener aquí export, const, github, icon.
Esto luego lo arreglaremos mejor, ¿vale?
Pero, bueno, por ahora vamos a hacer esto por aquí, esto por acá.
Y aquí vamos a pasarle class name.
Vamos a ponerle por defecto el que ya tiene,
para que no tengamos que estar ahí recreándolo, pasándoselo y tal.
Y class name y ya está.
Esto no es necesario.
No sé si lo sabíais, pero no es necesario los componentes de React.
Eso era cuando utilizabas los SVG de otra forma.
Ahí no lo necesitas.
Y iniciar sesión con GitHub, ¿vale?
Voy a ponerle, a ver, text white, hover, no sé qué, dark.
¿Ves?
Es que esto que tiene aquí dark, esto no tiene mucho sentido.
Así que vamos a quitarle el dark.
Y vamos a ver aquí cuáles son los que se repiten.
Este es uno.
Así que este fuera.
Vamos a quitar este.
Y ya está.
Vale, vamos a ver cómo ha quedado esto.
Vamos a ver.
Ah, bueno, espérate.
Porque aparte tendremos que renderizarlo, ¿no?
Así que vamos a poner el hola Twitter este.
Vamos a poner aquí el out button.
¿Vale?
Y al menos ya tendríamos esto por aquí, renderizándolo.
Bueno, tenemos.
Ahora vamos a mostrar los dos botones.
Luego lo cambiamos, ¿vale?
Para que solo se pueda mostrar uno de los dos.
Para que no haya ningún problema.
Iniciar sesión con GitHub, sync out.
Vale.
Al menos ya tenemos lo de los botones visuales y tal.
Pero, pero, es lo que os comentaba.
El problema es que si le damos, esto ahora, pues, me inicia.
O sea, me lleva a Guija para iniciar sesión.
Me dice, autoriza esto.
Le puedo dar a autorizar.
Esto redirecciona su pavés.
Pero el tema es que luego va a intentar redireccionar a este callback.
Y ese callback todavía no existe.
Entonces, vais a ver que esto va a pegar un 404.
Porque, fijaos, veis que aquí pone code, no sé qué, no sé cuánto.
Aquí lo que nosotros tenemos que hacer es crear un endpoint.
Entonces, ¿qué necesitamos?
Tenemos que crear aquí la ruta, auth, ¿vale?
Vamos a poner aquí auth, auth, callback.
Y aquí, para que esta ruta responda en Next.js,
tenemos que decirle que esto es un root.ts.
Así es como se crean los endpoints de la API en Next.js.
O sea, para crear una API en Next.js,
tú puedes crear la estructura de carpetas que te dé la gana
y luego terminar con root.ts.
Y esto lo que te permite es acceder a esto como si fuese una API.
Y aquí, para que crees la API, pues puedes hacer export async function
y el nombre del método que quieres que responda.
Puedes utilizar post, puedes utilizar put, patch.
Aunque en este caso vamos a utilizar el get.
Vamos a poner next request como tipo.
Estamos utilizando TypeScript, así que necesitamos tipar las cosillas.
¿Por qué guardas la sesión en cookies y no en local storage?
¡Qué buena pregunta!
A ver, por diferentes motivos, ¿no?
Lo primero es que realmente las cookies son un poquito más seguras
que local storage, ¿vale?
Eso es lo primero.
Lo segundo es que realmente para local storage
no puedes leer local storage desde el servidor.
Y muchas veces te interesa justamente poder leer las cookies
para saber si el usuario ha iniciado sesión.
De hecho, lo hemos hecho antes.
Fíjate aquí que Supabes, para crear, para poder saber
si el usuario ha iniciado sesión, lo que hace es leer las cookies.
Fíjate, en esta línea.
Y como le pasan las cookies, lo que quieres justamente
es poder guardar en las cookies esta información
porque no le puedes pasar en el servidor el local storage.
¿Entendéis?
Muchas veces el tema del local storage normalmente
se hace porque hacéis SPAs en el cliente.
Pero si quieres leer algo en el servidor
es que vas a querer utilizar cookies casi seguro.
Puedes hacer que las cookies sean HTTP only,
que solo se puedan leer en el dominio en concreto.
Tienen un montón de temas que son bastante...
que hacen que sean un poco más seguras justamente que el local storage.
No lo hacen impenetrable, ¿vale?
Pero sí que las hacen un poquito más seguras.
En local storage tú no puedes hacer un HTTP only.
Y además de hacerlas un poco más seguras
es que también funcionan con server site.
Cosa que el local storage, a no ser que la envíes,
no lo puedes hacer, ¿vale?
A ver, lo primero que tendríamos que hacer en la ruta
es crear también un cliente.
Fijaos que para todos los clientes que tenéis que crear de Superbase
hay todos un create root handler, create server component, create...
Los tiene todos, los tiene todos.
Y eso está muy bien porque al final así es súper fácil
cómo lo tienes que hacer.
También vamos a necesitar las cookies como lo hemos hecho antes
y se las tenemos que pasar justamente para crear el cliente
y para crear esta conexión.
Así que primero vamos a crear aquí en Superbase
el create root handler
y lo que le vamos a pasar no es la request,
son las cookies, ¿vale?
Exactamente lo mismo que hemos hecho antes.
Y aquí atendíamos el cliente de Superbase.
Y aquí podríamos hacer lo de esto que voy a hacer.
Lo tenéis para que veáis, ¿no?
Estaría exchange code.
Lo tenéis aquí.
Aquí, ¿veis?
O sea, me lo podría copiar directamente.
O sea, esto me lo puedo copiar y pegar y funcionaría.
Pero bueno, si queréis me lo copio y os lo explico.
Pero es exactamente lo mismo.
¿Qué es lo que hace?
Importar todas las dependencias.
El force dynamic este básicamente es para que no cachee la ruta.
Cosa interesante.
No lo había pensado.
La verdad es que esto se me había escapado.
Esto es una cosa.
Esto es una opción.
Esto es una opción de Next.js para evitar que cachee de forma estática la ruta.
¿Vale?
Aunque, ¿y que siempre se ejecute en el servidor?
Bueno, sí, que siempre se ejecute en el servidor.
Porque así siempre vamos a tener seguro que esto se va a tener que ejecutar.
No lo va a cachear.
Y tiene sentido.
Pero la verdad es que teniendo en cuenta que la request va a cambiar y que el código va a cambiar.
No sé hasta qué punto esta línea es necesaria.
Pero bueno, la voy a poner para curarme el salud.
¿Qué es lo que hace aquí?
Bueno, si os fijáis aquí en el 404.
Fijaos que le ha enviado un código.
Un código aquí que tiene un código.
Pues este código es el que tenemos que acceder.
Y por eso estamos haciendo esto.
En la request.url tenemos que acceder a esta URL.
¿Vale?
Y luego leemos este código.
¿Qué es lo que estamos haciendo aquí?
Esto es de la plataforma web.
Que muchas veces la gente me dice,
ay, es que esto es muy complicado de Next.js.
Esto no es Next.js.
Esto es la plataforma web.
Esto, fíjate que es un objeto nativo.
Y fíjate que te enseña aquí la documentación de MDN.
Para poder crear una instancia de URL.
Y aquí puedes tener acceso a los search params.
Esto no sé por qué mucha gente todavía no lo usa.
Pero es que esto es increíble.
Porque así lo que puedes hacer es acceder al query string.
Sin tener que utilizar regex ni cosas raras.
¿Vale?
Y entonces ya teníamos aquí este código.
Que es el código que teníamos aquí en la URL.
¿Vale?
Ahora, está bien que hagamos este check.
Oye, si no tenemos código.
O si code es igual a null.
Entonces hacemos una cosa, ¿no?
Podemos hacer algo.
Por ejemplo, podemos devolver.
¿Ves?
Aquí, por ejemplo, dice que si tiene código, haz algo.
Y si no tiene código, haz esto.
Vale.
Tiene más sentido, ¿no?
Mirar primero si tiene código.
Y hacer estas dos líneas.
La primera, crear el cliente de Supabes.
Que lo había hecho aquí.
Pero lo podemos meter aquí.
Porque es solo si tenemos código.
Entonces es que vamos a crear el cliente de Supabes.
Así, eso que te evitas.
Y luego tenemos que hacer esta llamada.
¿Esta llamada qué es lo que hace?
Esta llamada lo que hace es, usando el código que le hemos pasado por URL, nos devuelve la sesión del usuario.
Y esto lo está haciendo.
Que cuando ves que está utilizando Authcode Use During the Packet CE Flow.
Este flow es el que hemos hecho con Github.
Que hemos ido a Github.
Que entonces eso ha generado la sesión.
Se la ha pasado a Supabes.
Ha creado el usuario.
Y nos está dando este código de aquí.
Esto es algo interno que ya está haciendo Supabes por nosotros.
Muy sencillo.
Solo tenemos que hacer una vez.
Y nos olvidamos.
¿Vale?
Entonces tenemos que hacer esto para que nos devuelva la sesión del usuario.
Con esto ya lo tendríamos.
Y ya podemos devolver directamente una respuesta de Next.
Y le decimos que nos redireccione.
Podemos decirle que vaya a Home, por ejemplo.
Hostia, el Next Response no lo he traído.
Ah, vale.
Pues hay que traerlo aquí.
¿Vale?
Y este NextCookies.
Ay, es que es Headers, no es Cookies.
Seguro que me lo habéis dicho.
¿Vale?
Si Code es diferente a Null.
¿Vale?
Hacemos esto.
Y entonces respondemos esto.
Y aquí tenéis una opción.
Una, podéis hacer esto.
Que sería devolverlo a la Home.
O podéis utilizar algo bastante interesante.
Que es decir, bueno.
Si la request que ha hecho el usuario.
Pues era desde barra profile, barra lo que sea.
Y ha iniciado sesión desde ahí.
Pues lo que podemos decirle.
Es que le devuelva al origen.
Y el origen aquí, pues depende de la página que haya sido.
Le llevará a un sitio o a otro.
Si lo queréis simplificar ahora.
Pues podéis decirle barra y siempre lleva a la Home.
Pero lo más correcto siempre es devolver al usuario en la página en la que estaba.
¿Vale?
No lleváis a cualquier sitio ahí súper raro.
Entonces, con esto.
Con esto se supone que ya seríamos capaces de ver si hemos iniciado sesión.
¿Vale?
Así que vamos a volver aquí a nuestro Superb.
Donde hemos creado localhost 3000.
¿Vale?
Inicia sesión con GitHub.
Me debería...
Bueno, no vamos a ver lo de GitHub.
Vale.
Parece que no ha hecho nada.
Parece que no ha hecho nada.
Pero si vamos aquí.
Vamos a ver en la aplicación.
Application.
Cookies.
Fíjate.
Aquí que tenemos esta cosa aquí.
Súper bestia.
Este Supabase Auth Token.
Esto significa que ya tenemos token.
O sea, que ya ha iniciado sesión el usuario.
Luego, lo que vamos a hacer es que si el usuario ha iniciado sesión.
Que se vea un botón o se vea el otro.
Podríamos intentar en el renderizado condicional, como esto es un componente de cliente, una cosa que podríamos intentar es hacer aquí un useEffect.
¿Vale?
Hacemos un useEffect aquí.
Y podríamos decir, preguntarle directamente.
Oye, vamos a recuperar la sesión del usuario.
Y aquí preguntamos a Supabase.
No le decimos, venga, Supabase.
Cuéntame.
Si vamos a esperar que Supabase.ad.getSession.
Vamos a recuperar la sesión del usuario.
Vamos a crear aquí un state.
¿Vale?
Para tener la sesión.
SetSession.
UseState.
¿Vale?
UseState.
UseState.
Importa.
Aquí podríamos guardar la sesión, el tipo, ¿vale?
O también puede ser null.
Claro.
Esto podría ser null.
Así que vamos a poner por ahora null.
Y la sesión, getSession.
Aquí podríamos guardar la sesión.
Que creo que, bueno, data ya debería ser null, ¿no?
No se puede asignar tipo session.
Ah, porque claro, esto hay que sacar data.session.
Y esto lo llamamos aquí.
GetSession.
Y esto solo cuando se monta por primera vez.
Si estás flipando con este UseEffect, mírate mi curso de React que lo entenderás.
Bueno, tenemos un efecto que la primera vez que se monta este componente, lo que estamos
mirando es, oye, recuperar la sesión del usuario.
Y dependiendo de la sesión del usuario, si tenemos sesión, mostramos uno.
Si no tenemos, mostramos el otro, ¿no?
Y ahora aquí podemos decir, vale, si la sesión es igual a null, entonces, pues, renderizamos.
Si es igual a null, tenemos que hacer el login.
Así que vamos a traernos este botón de aquí, ¿vale?
De hecho, lo vamos a hacer así, que tiene más sentido.
Y si no, pues, le vamos a poner este botón de aquí, ¿vale?
Pam, pam, pam.
Con esto es, si la sesión es null, significa que el usuario no está logueado.
Por lo tanto, le decimos que inicie sesión.
Si no es null, es que ha iniciado sesión y entonces le damos el sync out, ¿no?
O vamos a cerrar sesión, ¿no?
Cerrar sesión.
Cerrar sesión.
Vale, entonces, ves, ahora dice cerrar sesión, pero cuando le doy, cuando le doy, fíjate, le doy, estoy dando clic, no está pasando nada, pero si refresco, me sale lo de iniciar sesión, que esto está bien.
Si le doy a iniciar sesión, fíjate que como esto lo que hace es una navegación, sí que me aparece bien lo de cerrar sesión.
Pero aquí cuando cierro sesión, si vamos a aplicación, cookies, ves, aquí tengo cookies.
Si le doy a cerrar sesión, ves que me ha borrado una cookie, eso es porque básicamente ha detectado que he cerrado sesión.
El problema es que no lo está refrescando correctamente.
Podríamos hacerlo de diferentes formas, pero sería un poco rollo.
A ver, ¿cuál es el problema clave?
Y esto es uno de los problemas que suele ocurrir bastante.
El tema es que, claro, tendríamos que o suscribirnos a tener esto, poder suscribirnos y decir, bueno, cuando cada vez que cierre sesión, pues vamos a ver si realmente vamos a refrescar otra vez el componente.
Entonces, una cosa bastante interesante que podemos hacer es separar este componente en dos, ¿vale?
Este out button, que ahora mismo es todo cliente, podemos separar la parte del servidor y la parte del cliente.
Así que lo que podemos hacer aquí, vamos a crear aquí la parte como del client.
Ahora me preguntará si quiero actualizar las importaciones, por ahora le vamos a decir que sí.
Y lo que vamos a hacer es decir, bueno, vamos a separar en otro componente, en el out button server.tsx, ¿vale?
Vamos a tener aquí la lógica del servidor, si tenemos sesión o no tenemos sesión del usuario.
Así que vamos a importar todo esto, ¿vale?
Esto luego lo podríamos sacar.
De hecho, lo sacaremos seguramente.
Vamos a traernos el out button del client, que es todo esto que tenemos por aquí.
Y aquí export async function out button server, ¿vale?
Esta va a ser la parte del servidor.
Y en la parte del servidor vamos a crear nuestro cliente de Supabes con create server component.
Le pasamos las cookies.
Ahora le ponemos aquí data.
Vamos a recuperar la sesión, que lo podemos hacer directamente desde el servidor, ¿ok?
Ah, ay, las cookies aquí se las he pasado un poco de un inchis, ¿vale?
Entonces aquí hacemos await supabase.out.get session, ¿vale?
Recuperamos la sesión.
Esto es justamente lo mismo que habíamos hecho aquí.
Fíjate, lo que habíamos hecho aquí, ahora lo estamos haciendo aquí y lo estamos haciendo sin ningún tipo de estado.
Y ahora directamente ya lo que hacemos es renderizar el componente del cliente y le pasamos la sesión del usuario.
De forma que ahora esto, lo que hacemos es que en lugar de utilizar este efecto, lo vamos a pasar por aquí, aquí como prop.
Sesión, quitamos esto.
Fíjate que esto está, esto es lo chulo de React Server Components, porque esto te simplifica un montón el hecho de decir,
ostras, no necesitas tener un estado o un efecto.
O sea, la idea ahora es quitar los efectos, pasarlos al servidor, envolver el cliente o la parte del cliente que quieres que tenga esta información y ya está.
Y ahora esta parte la estás haciendo en el servidor, estás trayéndote la sesión, se la pasas por props y ya tienes esta parte aquí.
Y ahora lo que puedes hacer aquí, una vez que ya tenemos esta información, es decir, bueno, cuando cerremos aquí el SYNCOUT en el cliente,
lo que podríamos hacer es decir que actualice la ruta.
Lo vamos a ver ahora, este out button client.
Ah, ahora tenemos que renderizar el del servidor, ¿eh?
Aquí, ¿vale?
Aquí renderizamos el del servidor.
Teníamos ya todo esto con el SYNCOUT y ahora hacemos lo del navigation.
Porque vamos a ver por ahora si funciona, el de iniciar sesión por ahora funciona y ahora cerrar sesión, ¿vale?
Sigue sin funcionar.
Pero el tema es que ahora en cerrar sesión, aquí podríamos traernos el, ¿cómo se llama esto?
Next navigation, el use router, ¿vale?
Y le podemos decir que esta ruta la refresque.
Así que ponemos router, cuando hacemos el cerrar sesión, le decimos que la refresque, ¿vale?
Y ahora vamos a refrescar, iniciar sesión.
Esto ya funcionaba antes.
Cerrar sesión.
Le doy clic.
Y ahora sí que funciona, ¿vale?
O sea, que ahora sí que está comportándose como esperamos.
Que cuando le damos a cerrar sesión, lo que está haciendo es simplemente refrescar esta ruta
de forma que va a volver a renderizar este servidor que tenemos por aquí.
Va a traerse la sesión correcta y ya lo tendríamos.
Esto del next navigation, por si queréis información,
esto está documentado obviamente por la gente de Next.js.
Han dicho una cosa que está muy chula, esto de use app router y no sé qué.
A ver si la encuentro, next navigation, a ver, punto refresh, refresh.
Han dicho una cosa que está muy chula, no, fast refresh, esto, router punto refresh.
Aquí lo tenemos, ¿no?
La notion refresh de un router te puede manualmente refrescar una ruta,
pero fíjate que tú no has visto absolutamente nada.
O sea, no has visto un parpadeo ni has visto absolutamente nada.
Lo que está haciendo es, mira, pone, lo que hace es una nueva request al servidor
para la ruta actual, ¿vale?
Y esta es la clave, porque lo que estamos haciendo al hacer una nueva request
es que este componente va a tener la información actualizada,
va a enviarle la información de que ahora no tiene sesión
y solo esta parte se va a reconciliar y va a saber cómo sí que funciona correctamente.
Por eso no estás viendo ningún tipo de parpadeo ni nada,
porque la única parte del cliente que se reconcilia es la del botón.
Eso está muy interesante también, ¿eh?
¿Cómo rehidratar? Bueno, algo parecido, ¿no?
Los nombres de componentes no tenían que estar en mayúsculas.
¿Qué nombre de componentes?
Esto, no, no.
Bueno, a ver, podría estar como te dé la gana.
No hace falta que estén en mayúsculas.
De hecho, para mí, la forma más correcta de nombrar los archivos
es utilizando Kebabcase, que es lo que estamos utilizando aquí.
Esto es subjetivo. Podéis utilizar lo que os dé la gana.
Os lo he explicado un montón de veces, ¿no?
Ya os he comentado un montón de veces el hecho de que la forma más correcta
de tener archivos a lo ancho y alto del mundo de la programación
es utilizar el Kebabcase o el Snakecase, ¿vale?
¿Por qué?
Porque en realidad hay muchos sistemas operativos que son case-sensitive.
Y seguro que os ha pasado alguna vez que habéis tenido problemas
de tener un componente que lo habéis llamado lo que sea,
lo que sea punto TS.
Y luego lo importáis como from, yo qué sé, lo que sea punto TS, ¿no?
Y esto en local te funciona y luego en producción,
y luego en el deploy te peta, ¿vale?
Pues esto te pasa un montón de cosas.
Entonces, en los ficheros, la verdad es que lo mejor es utilizar
siempre el lowercase.
Para mí es objetivo que sea mejor, ¿eh?
Que hay cada uno que haga lo que quiera.
El useClient, ¿ese qué hace?
El useClient, este lo que hace es que este componente
se renderiza en el cliente, punto.
Ya está.
Lo que tenemos por aquí es que, por ejemplo,
este solo se renderiza en el servidor y, por lo tanto,
este JavaScript no llega al servidor.
Si lo quieres ver de otra forma, más clara,
si yo pongo aquí un console.log y pongo hola, ¿vale?
Fíjate que yo voy a ir aquí a la página
y si miro la consola, aquí no hay ningún hola.
Pero si me voy a la terminal, aquí sí que tengo un hola, ¿vale?
¿Por qué?
Porque solo se está renderizando en el servidor, pero no en el cliente.
Así que, por defecto, eso es un React Server Component.
En cambio, si tú le pones un useClient,
significa que este botón, outButton, ¿vale?
Si hacemos console.log y ponemos aquí un hola, outButton,
fíjate que si le doy a guardar y me voy aquí, ¿ves?
Hola, outButton.
Aparece dos veces porque estamos en modo de desarrollo y, bueno, ya sabéis.
Esa es la diferencia, que esto se está renderizando
en el cliente y en el servidor.
Y el otro no.
Podríamos hacer una ruta protegida
para que nuestro usuario no pueda venir a la home
a no ser que haya iniciado sesión.
Y así ponemos una ruta protegida,
que sé que se encantan las rutas protegidas.
Vamos a poner aquí una ruta que sea login page.tsx, ¿vale?
Vamos a poner export default function,
vamos a crear una página, login, ta, ta, ta, retur.
Y aquí, este outButtonServer que habíamos hecho aquí,
lo vamos a poner aquí mismo, a saco, server, ¿vale?
Para que al menos tengamos esto.
No me gusta que ponga esto.
Ah, ¿por qué no?
Ah, porque hay que utilizar el source barra app.
No me digas.
Hay que poner el barra app.
Es verdad.
Entonces, vamos a hacer una página que solo ponga esto.
Bueno, vamos a poner un poco más, va.
Vamos a poner un poquito más.
Yo qué sé, section.
Y ponemos class, grid, place content center.
Aunque creo que esto no va a funcionar del todo,
pero bueno, no pasa nada.
Y screen, ¿vale?
Inicia sesión en Depter.
Depter.
Esto lo movemos por aquí.
¿Y qué hacemos aquí?
A ver, esto en realidad está muy chulo lo de las rutas protegidas en NextGS.
Por ejemplo, si queremos que cuando entren a nuestro Twitter,
pues, oye, tienes que iniciar sesión.
Tenemos dos opciones, uno detectarlo, otro mandarle.
Por ahora vamos a ir muy a saco y le vamos a mandar a otro sitio
para que directamente tengan que ir.
Pero lo que podríamos hacer aquí es importar el redirect, ¿vale?
De, esto no sé por qué me ha cargado de aquí, de NextNavigation.
Ya ves que NextNavigation es lo que te permite hacer un montón de cosas
con el tema de las navegaciones, las rutas y todo esto.
Y podríamos detectar si tiene sesión el usuario.
Si no, lo podríamos hacer en el button server también.
Ah, que lo pienso, ¿no?
O sea, desde aquí, desde aquí, como tenemos esa información,
aquí directamente podríamos mirar, oye, si no tienes, si sesión es nul,
pues, vamos a hacer un redirect a barra login, ¿vale?
Como que el usuario realmente vaya a tener que loggearse.
Y aquí esto lo podríamos dejar exactamente igual.
Así que, ¿vale?
Si nos vamos a aquí...
Ah, no, claro, pero el login, claro, por eso no puedo poner el login.
Por eso no puedo poner el login.
Claro, porque si no va a haber un...
Claro, esto, como lo estoy utilizando también en el login,
pues, va a hacer ahí una vuelta.
Bueno, podríamos ver si la URL es la misma.
No me parece bien.
No me parece bien.
Vamos a...
Por ahora vamos a separar.
Ya tendremos tiempo de...
Como que de hacer no repetir código y tal.
Así que, por ahora, lo vamos a dejar donde creo que a lo mejor tiene un poquito más de sentido.
Vamos a ponerlo por ahora aquí, ¿vale?
De forma que no pida los posts si todavía no sabe si tiene acceso.
Y la redirección la hacemos a nivel de página.
O sea, que no pueda tener acceso a esta ruta.
Porque, claro, esto es un componente.
Y, claro, no tiene tanto sentido.
A nivel de componente, ese componente lo podríamos utilizar en cualquier sitio.
Así que, a nivel de ruta de la home,
que no pueda acceder a la home si la sesión...
¿Ves?
Aquí ya tendríamos esto, ¿no?
Vamos a poner esto un poquito más.
Class name.
Class name.
Vamos a poner txxl.
Font vault.
¿Vale?
Que inicie esto un poco.
Cuatro.
Vale.
Entonces, si por lo que sea el usuario ahora intenta ir...
Fíjate.
Si intentas ir a la home, ¿ves?
Me redirige al login.
O sea, no hay otra.
Tengo que ir al login.
Y aquí, entonces, ahora la home, si no tienes la sesión iniciada,
haces una redirección del login.
Esto está muy chulo de los React Server Components de Next.js
porque antes hacer redirecciones era un poco rollo.
Y aquí puedes hacer la redirección en cualquier punto.
Si, por ejemplo, no hay sesión, si no existe el post, el usuario, el perfil,
puedes hacer un 404, redireccionar y tal.
Si iniciamos sesión, ¿vale?
¿Ves?
Ya me ha llevado aquí otra vez a la home.
Así que, si cierro sesión, ¿ves?
Me lleva al login.
Inicio sesión.
Y volvemos otra vez a la home.
Así que, bueno, al menos ya tenemos una ruta protegida.
Y esto que hemos visto de rutas protegidas,
pues lo podríamos hacer en diferentes sitios.
Vamos a empezar a crear los tuits que se vean visualmente,
porque obviamente esto no lo vamos a vender muy bien.
Para poder crear un tuit, o sea, para que se vean bien
y que los podamos maquetar, el problema es que si vamos a Twitter,
lo que necesitamos es el avatar, el nombre del usuario, el username.
Esto es el created ad, no hay problema.
El contenido, esto, o sea, tenemos el contenido y tenemos cuando se ha creado,
pero no tenemos el usuario, ¿vale?
Así que ahora hacemos el usuario.
Vamos a insertar la columna.
Por ahora vamos a hacer esto.
User ID.
Fijaos que aquí pone Add Foreign Key Relation.
Por eso muchas veces os digo que, joder, que tenéis que aprender SQL,
porque todo el tema de relaciones, de llaves foráneas y tal,
esos son conceptos que es que son universales
y que a la mínima te va a aparecer aquí en Superbase
y que vas a decir, ostras, que necesito aprender esto, ¿sabes?
Add Foreign Key Relation.
Bueno, pues aquí tenéis, por ejemplo, Auth, ¿vale?
En Auth es donde se están guardando los usuarios.
De forma automática, mira, vamos a ver esto primero.
De forma automática, cuando tú te inicias sesión en Superbase,
mira aquí en esquema, fíjate que tienes Auth.
Y en Auth tienes diferentes tablas.
Y una de ellas es la de users.
Y en users tienes ya un montón de información.
El UID, si está autentificado, el email, el password encriptado.
Hay un montón que, por lo que sea, no puedo hacer scroll.
¿Por qué no puedo hacer scroll?
Ahora, gracias.
Alguien me ha dicho con las teclas.
Joder, pero ¿por qué no puedo hacer...?
Mira, fijaos aquí, ¿veis?
Row App Metadata.
Aquí hay información como el avatar de GitHub, un montón de cosas, ¿vale?
Así que vais a ver que esto es súper útil.
Entonces, ya se ha creado una tabla automáticamente.
Y como tenemos una tabla con la asidez del usuario,
pues justamente aquí en los posts podríamos decir,
oye, pues vamos a crear aquí un user ID donde creamos Add Foreign Key
con el esquema Auth a la tabla que nos referimos es la de users.
Y que creen una relación en que cada tweet es de un usuario, ¿vale?
Así que aquí en las columnas le decimos el ID del usuario.
Y aquí nos dicen, oye, ¿y qué pasa si el usuario se borra?
¿Cómo tiene que actuar esto?
¿Sabes? ¿Qué acción tiene que hacer?
Puedes hacer que haya un... que se borre en cascada,
que se deje en null, que se ponga un valor por defecto.
Esto lo habréis visto porque es interesante, por ejemplo, en Twitter.
¿Qué ocurre si se borra un usuario?
Pues hay veces...
En Twitter yo creo que se borran todos los tweets.
Pero seguro que has visto un montón de servicios
que entonces se pone por defecto como si fuese anónimo y cosas así.
Pues esto es como se está haciendo aquí.
Aquí es lo que tú podrías decidir.
Aquí le vamos a poner cascade, obviamente,
porque vamos a querer que se borre todo.
Así que le damos a save.
Y aquí ya nos dice si es UID.
Y nos dice allow nullable.
O sea, esto puede tener un valor que sea null.
En este caso, por desgracia, tenemos que decirle que sí.
Porque si yo le digo que no y le doy a save, me peta.
Efectivamente, porque ya hay registros.
Entonces, como ya hay registros, no lo podemos hacer nullable.
O sea, no podemos dejar valores null porque ya hay registros que existen
y que, por desgracia, necesitan un valor.
Así que, claro, vamos a tener que empezar con allow nullable.
Guardamos.
Ahora sí que funciona.
Y ahora aquí lo que decimos es, venga, editamos
y vamos a elegir qué usuario es el que tiene estos tweets.
Entonces, añadimos aquí que es mi usuario
porque es el único que tenemos ahora mismo.
Y ya estamos creando una relación de que cada tweet es de un usuario.
Ahora, si volvemos a nuestra pedazo de aplicación de Twitter,
fíjate, ya tenemos el user ID.
Hasta aquí bien, ¿no?
Hemos creado esta relación.
Parece que todo funciona bien, pero esto realmente no funciona del todo.
No hace exactamente lo que queremos.
Porque para extraer información de las relaciones de las tablas
en Superbase, hacemos esto, ¿vale?
Hacemos el from, post.
Y aquí tendríamos que decirle, vale, quiero que de la tabla
out.users me saques, por ejemplo, el email.
Si yo guardo esto, ¿qué es lo que pasa aquí?
Ojo, me ha petado.
Me peta porque no tenemos permisos y no hay permisos que existan,
no existe ningún permiso que te permita acceder a los usuarios, ¿vale?
No hay ningún permiso que te permita esto.
Así que tenemos que crear una tabla pública de usuarios.
Así que sígueme con esto, que esto, lo bueno es que lo aprendes una vez
y no lo vas a tener que hacer nunca más.
Esto es una de las cosas que a mucha gente le echan para atrás de Superbase,
pero si dominas esto, lo desbloqueas todo, te lo aseguro, en serio.
Y lo bueno es que lo haces una vez y ya lo tienes.
Bueno, lo primero que vamos a hacer es volver a poner aquí que esto no sea
nullable, ¿vale?
Esto lo quitamos, que ya no lo necesitamos, así que save, lo quitamos y ya está.
¿Qué necesitamos hacer?
Vamos a tener que hacer una tabla que sea pública de usuarios.
Así que creamos una tabla que le llamamos users, ¿vale?
Activamos el role level security, como hemos hecho antes,
y ponemos aquí que la idea sea un UUID, porque esto tiene que ser un UUID,
un identificador único, porque es justamente el mismo que vamos a utilizar,
que vamos a traer del usuario que tenemos privado, ¿vale?
Y este tiene que estar referenciado a el AUTH, USERS y a la IDE.
Y aquí hacemos lo mismo, que se borre en cascada.
O sea, si alguien, si se borra el récord del AUTHUSERS,
también se borrará el público.
No tiene sentido guardar el público cuando estamos borrando al usuario, ¿vale?
Así que esta referencia la dejamos.
El cuándo se ha creado, lo podríamos dejar, no es muy interesante.
O sea, cuándo se creó el usuario, bueno, lo podemos dejar, no hace daño, ¿vale?
Lo que vamos a necesitar es, por un lado, el nombre del usuario,
que esto va a ser el texto, ¿vale?
Y aquí el texto, bueno, el name, no puede ser null.
También vamos a tener, por ejemplo, el username.
Y el username tampoco puede ser null, va a ser un texto, ¿vale?
Y no puede ser null.
Y finalmente vamos a tener también el avatar URL,
que esto también va a ser un texto,
porque no hay del tipo HTTP, URL o lo que sea.
Y esto también es nullable, ¿vale?
Esto va a ser nuestros usuarios públicos.
Importante, público.
¿Y por qué no ponemos, por ejemplo, el email?
Pues porque el email, ¿qué pasa?
Que si vamos a creer que esto sea una tabla pública,
en la que, por ejemplo, cuando tú entras a un perfil de Twitter,
ves la información del usuario,
su nombre, el username, su avatar y tal,
eso sí que es información pública,
pero a lo mejor su email no lo es.
Para simplificarlo, puedes tener, básicamente,
la información que quieres que sea pública en la tabla pública,
que te va a facilitar cuando enseñes los tweets,
puedes recuperar la información de cada usuario
y la privada la dejas privada.
Si no, también lo podrías hacer a base de políticas
y decirle que solo ciertos campos lo puedas hacer y tal,
a base de checks, todo se puede conseguir.
Pero lo haces un poquito más complicado.
Entonces, por ahora, tendríamos esto, ¿vale?
Creamos la tabla users, lo ponemos por aquí,
le he puesto el nombre users, ¿vale?
Añadimos las cinco columnas, ¿vale?
Ya tenemos los usuarios.
Vamos a hacer una cosa, vamos a borrar el usuario
que habíamos creado antes de autenticación,
no, ¿dónde está?
Aquí, en users, lo podéis borrar desde aquí,
por ejemplo, delete user, que soy yo,
lo borramos y entonces ahora habremos borrar el usuario.
¿Qué es lo que vamos a hacer?
Lo que necesitamos hacer es una función, ¿vale?
Lo que queremos es que cada vez que un usuario se registre,
automáticamente generemos en la tabla users
un registro con el usuario público.
Esto es súper típico.
Esto que vamos a hacer, tema rollo full stack developer,
es súper típico, ¿no?
Porque necesitamos muchas veces triggers.
Si no sabes lo que es un trigger,
hicimos el curso de SQL,
donde creábamos justamente la base de datos de Twitter.
En este curso lo aprendimos.
En una hora lo tenéis, que está súper chulo,
y aprendimos a hacer triggers, inserts, selects.
Y el tema de los triggers es que es clave muchas veces.
¿Qué son los triggers?
Los triggers básicamente es,
oye, cuando ocurra una cosa,
por ejemplo, cuando se inserte un usuario en esta tabla,
quiero que hagas otra cosa, ¿no?
O cuando se da like aquí,
quiero que incrementes el contador allí.
Cuando haces esto, hacemos...
¿Sabes? Un montón de cosas.
Bueno, pues este tipo de cosas lo vamos a tener que hacer,
porque queremos que cada vez que se cree un usuario,
también se cree en la tabla pública, ¿no?
¿Cómo lo podemos conseguir?
Pues por suerte, Superbase, esto lo tiene súper bien.
Mira, en Database tenemos aquí las functions, ¿vale?
En las funciones podemos crear funciones que son como,
si sabes MySQL,
es algo parecido a la Store Procedures, ¿vale?
O sea, son como comandos que se ejecutan cuando quieras.
O sea, es una función que dices, vale,
¿qué es lo que tengo que hacer?
Y esta función tú la puedes llamar cuando tú quieras,
o para controlar algún flujo,
o para hacer variaciones, checks, constraints, un montón de cosas.
En este caso lo podemos llamar aquí,
insert user in public table for new user.
El esquema es público,
y lo que devuelve va a ser un trigger, ¿vale?
No puedes devolver un record, un enter, un boleano,
pero en este caso lo que necesitamos es un trigger, ¿vale?
La definición de lo que queremos hacer,
aquí podemos decir dónde empieza, dónde acaba,
y lo que tenemos que hacer aquí, esto,
esto lo vimos casi igualito,
lo vimos en la clase que te comentaba, ¿vale?
Queremos insertar en la tabla que le vamos a decir,
le tenemos que decir en qué tabla queremos insertar.
En la tabla pública de users queremos insertar,
por un lado, la id, el nombre, el username y el avatar url.
Y voy a revisar que estos son los nombres correctos
que le he dado a los campos antes de liar la parda, ¿vale?
Porque si no, si no esto, luego son unos jajas.
Id, created at, name,
bueno, created at no es necesario y tiene un valor por defecto, ¿vale?
El name, username y avatar url, ¿vale?
Los he puesto bien, perfecto, ¿vale?
Queremos insertar en estos campos, ¿vale?
Los valores y le tenemos que decir de dónde sacamos estos valores.
La id lo vamos a recuperar de un objeto que es el new.id.
Este new es el nuevo objeto que es el que,
cuando detectamos el trigger, es como el nuevo que se ha creado.
Y entonces podemos acceder a su información,
sus propiedades y todo, ¿vale?
Entonces vamos a querer que la id del usuario privado pase a la pública, ¿vale?
Luego, el new también, como hemos visto antes,
tenemos información de metadatos.
Entonces pasamos a raw metadata, ¿vale?
Y esto lo voy a revisar porque nunca me acuerdo si es así.
Managing, vale, ves, raw user metadata.
Esto es un objeto que tiene toda la información del usuario,
como por ejemplo el nombre, el username, el avatar url y todo esto.
Y de aquí vamos a acceder a la propiedad de name.
Ojo con esto, que esto a lo mejor te vuela un poco la cabeza,
el cómo se accede, ¿vale?
Pero es así, es así, ¿ok?
Lo voy a buscar de hecho para asegurarme porque es un poco raro.
Pero ves prácticamente, vale, ves que existe, vale.
¿Qué es lo que hace esto?
Esto lo que hace es, esto es un objeto
y de este objeto estamos accediendo a la propiedad name.
Y esta barra de aquí, esta flechita, esto es de PostgreSQL,
que lo que hace es acceder a la propiedad y convertirla a texto.
O sea, no es que me la estoy inventando, no es que sea algo muy raro.
Esto, por desgracia, es algo que hay que saber de PostgreSQL y ya está.
¿Ves?
JSON, attribute, es not null.
Ves que hay como esta y esta.
Y la diferencia es que la de arriba te devolvería en JSON
y la de abajo te lo devuelve en texto.
Y en nuestro caso lo que queremos es extraer el atributo,
el valor del texto, ¿vale?
Así que por eso lo hacemos así.
Y esto lo repetimos tanto para, bueno, lo repetimos tres veces,
para el username, que creo que es este con guión,
el metadata, antes lo he visto que creo que era con guión,
y el avatar y URL que también era con guión.
La verdad es que podría haber puesto aquí también que esto fuesen con guión
para que fuese exactamente igual, pero bueno.
Y aquí lo terminamos con un punto y coma y devolvemos el nuevo objeto, ¿vale?
Así que insertamos en la tabla pública de usuarios con estos valores,
que estos los extraemos de el objeto que se está creando
en la tabla privada del usuario, traemos todo esto.
Luego te volveré a enseñar el objeto para que lo veas,
para que veas que es un objeto y por eso tenemos que hacer esto.
Y lo importante, que tiene que ser con dos flechitas
para que te devuelva el texto, ¿vale?
Porque si no te lo da en formato JSON.
Es decir, efectivamente, Joan Bar.
Aún no es demasiado tarde, lo puedes cambiar, ¿no?
Es que es un poco rollo, ¿no?
Tendría que ir al otro sitio.
Tendría que ir aquí.
A ver, venga, va.
Lo voy a cambiar, lo voy a cambiar.
Avatar URL, Username.
Vamos a cambiar la columna esta.
Username.
Vale, para que sea igual.
Es que si no es un poco rollo que en uno tenemos un sitio
y en otro en otro, ¿no?
Y aquí nos vamos a referir también con la Username
para que sea exactamente igual, ¿vale?
Con esto tendríamos la función.
Esto es solo la función, ¿vale?
Así que esto sería el operador para extraer el campo de texto, ¿vale?
Vamos a poner Show Advanced Settings porque aquí hay una cosa
que hay que cambiar.
¿Veis aquí que pone tipo de seguridad?
Es importante que el tipo de seguridad en realidad no sea el que invoca,
sino el que define la función.
O sea, esto lo que quiere decir es que los permisos de este comando
que veis aquí lo va a tener por quien ha creado la función,
no por quien está invocando la función, ¿vale?
O sea, no es lo mismo el que ha creado la función que el que llama la función.
Son dos personas diferentes.
Y en este caso queremos que los privilegios que tenga
es el que ha creado la función, que digamos que son los de administrador.
Así podrá crear sin ningún problema en la tabla public el campo que quiera.
Esto es bastante importante porque no es lo mismo a veces
que por tema de privilegios o permisos que la persona que invoca una función
a lo mejor tiene menos privilegios que la persona que creó la función, ¿ok?
Venga, confirmamos esto.
Vamos a ver que lo hemos hecho bien.
Y ahora justo encima tenemos triggers.
Creamos un nuevo trigger, ¿vale?
Y le podemos decir aquí cuando on out, cuando hacemos out,
el insert users.
No utilices espacios ni white space, ¿vale?
Condiciones para el trigger.
O sea, ¿cuándo se tiene que disparar esta función?
Pues cuando en la tabla, y buscamos aquí,
cuando en la tabla, ta, ta, ta, users out, ¿vale?
La de out, no la public, que la de public la he creado yo.
Cuando se registra un usuario, cada vez que se inserta un usuario,
lo que vamos a hacer es después del evento, no antes, porque antes no tiene sentido.
Imagínate que antes de que se inserte el usuario, por lo que sea, peta,
y ya hemos creado en nuestra tabla pública al usuario.
O sea, que tiene que ser después del evento.
Lo que vamos a hacer es que cada vez que se procesa una nueva fila,
o sea, que cada vez que se inserta un nuevo usuario,
lo que vamos a hacer es ejecutar la función que hemos creado,
que es la de insert user in public table for new user, ¿vale?
Puedes ver aquí la definición, por si tienes algún tipo de duda o pregunta y tal, ¿vale?
Le das aquí, y en principio, si no la he liado parda,
si no la he liado parda, con esto deberíamos ya tener esta conexión, ¿vale?
Así que le vamos a confirmar.
Voy a revisar rápidamente, ¿vale?
El user es este, es el out, ¿vale?
Que no la líe.
Cada vez que se inserta, perfecto.
Confirmamos.
Vale, ya lo hemos creado.
¿Qué significa?
Si vamos a tabla, users está vacío.
En post han desaparecido porque también hemos borrado el usuario.
Y en out podemos ver que en la tabla...
Ah, sí, la tenemos aquí, vale.
Pero está vacía también.
Ahora, si todo ha ido bien, y si no ha ido bien no pasa nada,
porque aprenderemos también a arreglarlo,
vamos a ir a localhost 3000, vamos a iniciar la sesión.
Iniciamos sesión con GitHub.
Y parece que aquí ha funcionado, ¿vale?
Parece que ha funcionado.
Si volvemos aquí a la tabla, nos ha creado el usuario privado, ¿vale?
Vamos a ver una cosa.
Para que veas el objeto que os decía, ¿no?
El row meta, no sé qué, no sé cuánto.
Lo tenemos aquí, row app metadata.
¿Veis?
¿Veis que es un JSON?
Lo pongo aquí, JSONB.
Que es JSONB significa que se guarda en formato binario.
Y aquí hay un montón, pero un montón de información
que es la que estábamos extrayendo.
De hecho, podemos ver un poquito aquí la información.
Ah, no.
Ah, es que este no es.
No me digas que me he equivocado.
Y he puesto user metadata, ¿vale?
Sí, sí, sí.
Claro, digo, me he equivocado ahora.
Vale.
Esta sería un poco la información para que le veáis un poco por encima.
Vale, pues aquí tendrías, ¿no?
Por ejemplo, el nombre, el email, el full name, username, avatar URL,
si el email está verificado, ¿veis?
Y el username, esta es la información que estaba sacando,
como habéis visto antes, con el new.row user metadata, ¿vale?
Y estamos sacando el name.
Lo estamos sacando justamente, ah, el name está aquí, ¿vale?
Lo estamos sacando de este objeto.
Esto parece que ha funcionado bien.
Si vamos a public y vamos a users, podemos ver que nos ha creado
también un usuario aquí con la información, el nombre,
el avatar URL y el username, ¿vale?
O sea, que ya tenemos aquí la información pública del usuario.
Lo interesante de esto es que ahora que lo tenemos de forma pública,
podemos irnos aquí a autentificación, políticas.
Esto es lo mismo que hemos hecho antes.
Y los usuarios, le añadimos una nueva row level security,
le decimos que los usuarios allow everybody to read users' information, ¿vale?
Pero la información de los usuarios pública, que nosotros queremos, ¿vale?
Así que hacemos true, review, save policy, ¿vale?
Ya tenemos la política.
Nos vamos para aquí.
Y veis que antes estábamos haciendo este aut users.
Pues ahora ya podemos utilizar directamente el users, ¿vale?
Hacemos este users.
Por ahora, vamos a decirle que nos devuelva toda la información.
Y si volvemos a las tablas, a los posts, creamos aquí un post,
ponemos aquí, hola, gente, ¿cómo estáis?
Ah, espérate, espérate, que hay que cambiar una cosa más.
Porque en la tabla de los posts, ¿veis que tenemos aquí el user ID?
Este user ID, tenemos que editar la columna porque ahora no vamos a relacionarlo.
A ver, no pasaría nada porque es el mismo user ID.
Pero aquí la relación, en lugar de hacerlo con el de out,
lo podemos hacer ahora con la que tenemos pública.
Así que vamos a las tablas públicas, al esquema público y a la tabla users.
Total, es la misma ID, no pasa nada, ¿vale?
También hacemos que se borre en cascada.
No sé si la habéis visto.
Aquí.
Que se borre en cascada en el caso de que se borre el usuario,
que también se borde todos sus elementos, ¿vale?
Y vamos a ponerle save, ¿vale?
Que no sea null, save.
Es lo mismo, pero bueno, así nos curamos en salud.
Insert y aquí, hola, Depter, le decimos seller record, sale el usuario nuestro,
hacemos el save, ya tenemos un usuario, vamos a insertar otro.
Por ejemplo, Aaron Musk se va a pegar de hostias con Mark, ¿vale?
Esto también lo va a tener este usuario, save, vale.
Perfecto, pues nos vamos a nuestra página y aquí ahora tenemos toda la información.
Pero ojo, aquí está en lo interesante, amigos, es que fijaos que ahora lo que tenemos
no solo es toda la información del tweet, también tenemos la información del usuario
que ha hecho el tweet.
O sea, hemos hecho un join directamente.
Fíjate que haciendo esto, lo que estamos haciendo es un join.
Su pavase, de forma totalmente automática, está detectando y diciendo, vale,
quieres recuperar todos los posts y me dices que de los usuarios también lo quieres
recuperar todo.
Y lo que está haciendo es un join automáticamente detectando que está haciendo
con el user ID, está populando el resto del objeto de users con la información del usuario
que tiene esta ID.
Obviamente, vosotros podéis hacer lo que queráis.
O sea, aquí lo que podéis hacer sería, por ejemplo, solo la ID, ¿no?
Entonces, ¿ves? Solo la ID.
Podéis aquí recuperar lo que queráis, pues el name y el avatar URL y el username, ¿vale?
Lo guardamos, ¿veis?
Y solo nos devuelve esa información.
Pues así lo tenemos, así lo dejamos y aquí tenemos la cosa.
Ahora vamos, obviamente, a hacer que se vea bonito.
Vamos a ver cómo es el diseño del tweet.
Seguramente lo pondré por aquí y le damos cañita, ¿eh?
Y usa Next UI para el componente del tweet.
Pero es que no sé si se va a aparecer mucho.
Pero es verdad que esta es la versión 2.0.
¡Ojo!
Ojo que esta tiene buena pinta.
Venga, me ha convencido.
Me ha convencido porque nos vamos a poder copiar esta, ¿eh?
Vamos a instalarlo en Next.js.
Total, quiero pensar que no tenemos ningún problema.
Create Next Manual Installation.
Esto es lo que queremos.
Vamos a utilizarlo.
Vamos a utilizarlo.
Creamos en ti, Next UI, ¿vale?
Voy a ir actualizando Tailwind Config.
Aquí nos dice que pongamos en el content, que pongamos esto.
Así que content, ponemos esto.
Los plugins, clase, Dark UI, en plugins.
Quitamos esto.
Y también hay que traerse esto de aquí.
¡Ay, no!
¿Por qué?
¿Por qué esto?
¿Por qué no es un import?
Import.
Espero que no me dé ningún problema esto porque...
Vale.
Y Setup Provider.
Esto en app.providers.
Aquí en app.providers.tsx, ¿vale?
Use Client.
¿Vale?
I Provider to Root.
Esto en el layout, entiendo.
O sea, que tenemos que ir aquí al layout.
Y nos dice que pongamos el class name Dark.
Bueno, esto soy yo porque es opcional también, ¿no?
Pero bueno, pongamos esto.
Providers.providers, ¿vale?
Va a tener todos los providers.
Providers.
Providers.
Vale.
Y, joder, ¿eh?
¿Cuánta cosa hay que hacer?
¡Cago en la leche!
A ver, no pasa nada, ¿eh?
Dice Public Hoist Pattern.
Dice, si estás utilizando PNPM, necesitas añadir este código en tu NPM RC.
Hostia, yo utilizo...
No sé por qué sería necesario ese, pero...
Pero vale.
Después de publicar, necesitas utilizar PNPM install para asegurarte...
¿Vale?
PNPM install.
Sí.
Venga.
Estoy haciendo otra vez el PNPM install.
Vale.
Se supone que ya lo tengo todo.
Vamos a ver si esto realmente funciona.
Para eso vamos a...
¡Uy!
Ah, vale.
Porque está haciendo la instalación.
Mientras hace la reinstalación es normal que no encuentre algún módulo y tal.
¡Hostia!
No encuentran ni sus declaraciones.
¡Reload window!
No sé por qué me ponía ese error ahí, pero no tiene sentido.
Ahora sí.
Vale.
Vale.
Vamos a ver si esto funciona.
Para eso nos vamos a ir al Login.
En el OutButton este.
Vamos a importar este Button.
Y vamos a ponerlo aquí.
Solo para ver que realmente funciona.
¿Vale?
Vámonos a nuestra aplicación.
Este, el clon.
Cerrar sesión.
¿Vale?
Parece...
Vale.
Sí que funciona.
Parece que sí que funciona.
Así que bien.
Ya tenemos NextUI.
Perfecto.
Yo había visto ahí una card que tenía buena pinta.
Que era esta de aquí.
Esta tenía buena pinta.
Tenemos que cambiar algunas cositas.
El body debe ir fuera del provider.
El body debe ir fuera.
A ver.
En realidad lo mismo da que da lo mismo.
Pero bueno.
Si te pone...
O sea, no importa.
Al final lo importante es que esté envolviendo lo que quieres.
Que es tu aplicación.
Bueno.
Pues con esto tendríamos el tweet.
Lo vamos a tener que adaptar.
Pero bueno.
Al menos nos sirve.
¿Cómo le llamamos?
Postcard.tsx.
Export function postcard return.
Vamos a ver este código.
¿Vale?
Show more.
Nos lo copiamos.
Y vamos a poner aquí postcard.
Este import react no lo queremos.
Use state.
Esto lo importamos nosotros directamente.
Use state.
¿Vale?
Is follow.
Vale.
Esto no es...
Como tal no va a ser necesario.
¿Qué información le tenemos que pasar a nuestras cards?
Por un lado el username.
Por otro lado el avatar URL.
Eso seguro.
Y el name.
User full name.
Y todo esto vamos a hacer que string, string, string.
Luego lo arreglaremos.
Lo haremos bien porque generaremos los tipos y esto lo podremos reutilizar.
Vale.
Madre mía.
La de cosas que hay por aquí.
Vale.
Ah, y el contenido, claro.
El content, ¿no?
El content también lo vamos a necesitar.
Content.
Esto va a ser un string.
Entonces, vámonos a nuestro page.
No.
Nuestro page.
Este no es.
Vámonos al page aquí.
Que aquí estamos renderizando los tweets, ¿no?
Vale.
Estos tweets por ahora vamos a hacer posts.map.
Y para cada post vamos a renderizar el post card.
Este.
Y le pasamos de cada post el post.id.
Y le vamos a pasar.
Claro.
Estaba pensando en pasarle a saco toda la información.
Pero, claro, no puede ser.
Porque tenemos que sacar el username.
Y esto lo tenemos que mapear.
El name.
Que sea el user full name.
Y el avatar URL.
Que será el avatar URL.
Y esto lo sacamos de post.
A ver.
Identificador post está duplicado.
A ver.
Un momento.
Ah.
Porque me falta el return aquí.
Vale.
Ya está.
Vale.
Esto lo quitamos aquí.
Y ahora sí.
Ya podemos.
Ya podemos pasarle todo esto.
Return.
Lo vamos a migrar aquí.
Tendríamos el username.
Con el username.
¿Sabéis una cosa?
Que me da mucho coraje de React.
Y que no lo han puesto porque no le sale de las narices.
Y me da un coraje exagerado que no lo hagan, tío.
Porque no lo hacen por rabia.
¿Sabes?
No lo hacen por rabia.
A ver.
No lo hacen por rabia.
Y porque se supone también que dice que había problemas con no sé qué.
No sé cuánto.
Pero no sé.
No me convencen a mí.
¿Vale?
Y me faltaría el content.
Que esto sería el content.
¿Vale?
Content.
No.
¿Cómo era?
¿Cómo se llamaba esto?
Content.
Content.
Ah.
Es que sabéis.
Me falta una cosa que vamos a hacer ahora.
Vamos a hacer ahora porque esto es un poco rollo.
El tema de que no tengamos.
Si os fijáis.
El post.
¿Veis que pone any?
Esto es un rollo.
Porque no tenemos los tipos de TypeScript.
Pues esto tiene solución y lo vamos a arreglar.
¿Vale?
Una cosa que me da mucha rabia es el hecho de que molaría que en React se pudiera utilizar esto.
¿No?
Que una vez que sabes que el key y el value se puedan utilizar igual, que lo pases así y ya está.
Se pueden hacer cosas un poco piratas.
Que a mí normalmente no me gustan.
Como esta.
De decirle.
Bueno.
Pues creamos aquí un objeto y le pasamos todas las propiedades de este objeto.
Que sea esto.
Y así pues te puedes evitar como el tener que repetir y tal.
No me gusta mucho porque se ve muy hacky la verdad.
Pero bueno.
Si queréis una alternativa que sepáis que esto lo podéis hacer.
Para no tener que repetir los nombres.
Pero bueno.
Entre esto casi que prefiero esta.
Aunque lo que me gustaría es que sí que aceptase la forma, el short hand que sí que se puede hacer.
Al menos con esto ya tenemos los postcards.
Ahora se verá regular.
Pero ya iremos ahí ajustando.
¿Vale?
Así que vamos al localhost 3000.
El useState.
Esta es la que necesita state.
Y solo funcionan los client components.
Tienes toda la razón.
También es verdad que este useClient.
Claro.
Veis que aquí no pone use.
O sea.
Aquí debería poner useClient.
Pero realmente necesitamos.
Bueno.
Sí que vamos a editar.
Por ahora lo voy a poner.
Aunque más adelante vamos a ver que no lo vamos a editar tanto.
¿Vale?
Vale.
Iniciamos sesión.
No sé por qué.
No sé si voy a hacer la sesión antes.
Vale.
Card footer is not defined.
Ah.
Y la demo está mal.
Card footer is not defined.
Mira.
Pues ya le podéis hacer una PR.
Para que ponga el card footer.
Que no lo tenía.
Por aquí van un poco los tiros.
Todavía no está bien.
Porque me faltan cosas.
O sea.
No se ve la información.
Por ejemplo.
Del avatar.
Is followed.
Esto.
Este botón.
Por ejemplo.
El follow.
Este nos sobra.
No lo vamos a utilizar.
Fuera.
Luego.
Aquí.
Frontend developer.
En realidad.
Claro.
Esto sería el contenido.
En todo caso.
Este sería el content.
Esto de aquí abajo.
Claro.
Es que parece más una card de sígueme que no el tweet.
Pero bueno.
Ya nos ha servido al menos.
Para empezar con algo.
¿Ves?
Hola adapter.
Aquí tendríamos.
Por ejemplo.
En avatar.
Tendríamos que poner el avatar URL.
URL.
¿Vale?
Y ya al menos tendríamos.
Oh.
¿Por qué sale eso?
A ver.
El avatar.
Avatar URL.
No me está devolviendo.
Igual algo ahí que no.
No hemos terminado de ajustar.
Avatar.
Vamos a ver esto.
¿Qué está pasando aquí?
Ah.
Undefined.
Vale.
¿En qué sitio se me ha escapado esto?
Avatar URL.
Avatar URL.
Esto lo estamos sacando.
Ah.
El hecho es que el post dentro de user es que está la información.
O sea.
Esto es.
Sacamos la idea.
El content.
Vale.
Vale.
Y esto lo sacamos de post.
Y dentro de user es que sacamos esta información.
¿Vale?
Esto funciona así.
¿Tenéis razón?
Sí.
Pero en este caso no os apuntáis el tanto.
A ver ahora.
A ver ahora.
It's undefined.
Vale.
Porque no es user, es users, me parece.
Esto es otro tema interesante.
¿Vale?
Es que esto no es users, sino que será users.
Para cambiarle la información.
¿Veis que pone aquí users?
Claro.
Porque la tabla se llama users.
Y cuando hace el populate, cuando te rellena esa parte del objeto, te pone aquí el nombre.
Creo que puedes renombrarlo utilizando dos puntos.
O sea, puedes utilizar users, dos puntos.
Y este sería el nombre de la tabla.
Y estos los campos que quieres extraer.
Creo que con esto puede ser.
¡Ojo!
No sé por qué hace una animación.
Un poco raro.
Pero bueno.
Me sirve.
Me sirve.
Venga.
Vamos aquí.
Este sería el name.
El user full name.
Y este sería el username.
Así que hacemos el username.
¿Vale?
Y ya tendríamos, empezaríamos a tener ya unas cuantas cositas.
El avatar.
Vale.
El avatar.
Esto en realidad debería ir al username.
Así que vamos a poner que es un enlace.
Que va a esto.
El avatar lo movemos.
Lo movemos por aquí.
Le vamos a quitar isborder.
Porque creo que en Twitter no tienen borde.
Así que perfecto.
¿Vale?
Y aquí este gap me parece que es un poco exagerado.
Vamos a ponerle un poco menos.
¡Hostia!
¿Dos?
Igual dos puede ser.
¿Vale?
A mí que esto sea tan la pesta.
Text default.
Esto vamos a ponerlo que sea más blanquito.
White.
¿Vale?
Muy bien.
Ya van por ahí los tiros.
Ya van por ahí los tiros.
Al menos luego los estiraremos que pille todo el width.
¿Vale?
Que tengamos toda la sección de los tweets.
Pero bueno.
Al menos ya tenemos ahí algo.
Y esta parte de aquí en realidad no la necesitamos así.
Vamos a instalar un paquete de iconos.
Que a mí me gusta bastante.
Que es Tabler Icons.
Cuidado con esto.
No utilicéis el de arriba.
El de arriba está mal.
El de arriba es incorrecto.
No está mal.
¿Vale?
Tabler Icons y Tabler Icons.
Vale.
El de 4600 es el bueno.
Este es el bueno.
Esta es el bueno.
Además tienes Sponsor Project.
Y unas cosas buenas que tiene.
Aparte que tiene 4600 iconos.
Para mí es la mejor de iconos que existe de aquí a Lima.
Tiene también paquetes para Ria, por supuesto.
Así que vamos a utilizar este de Ria.
Lo vamos a instalar aquí.
Una cosa que me gusta mucho de Tabler Icons es que tiene más de una versión del mismo.
Por ejemplo, tú pones Home y ves del sofá.
Tienes el sofá y lo tienes también como tachado.
Pero tienes el sofá en dos versiones.
En esta y en esta.
Eso me parece un detallazo, ¿sabes?
De tener más de una versión del mismo icono.
Me encanta.
Aquí en este caso, pues, ¿qué necesitamos?
Si vamos a Twitter, necesitamos tú, tú, tú.
El, no sé cómo será.
Responder.
Reply.
A ver si lo tiene.
Además el buscador, no sé, me gusta mucho.
Mira, teníamos el reply.
Pero veis que esto, bueno, estos dos parecen el mismo, ¿no?
A mí me parece el mismo, pero bueno.
Cositas.
Puedes copiar SVG.
Y también con esto, este sería el nombre de Ria.
¿Ves que pone Icon Message Circle aquí?
Pues nada, con eso ya lo tendríamos.
Así que ahora haces aquí, así, from Tablet Icons y ya lo tendríamos.
Y aquí, pues, ya podríamos empezar a poner todos nuestros iconitos.
Por ahora vamos a poner los iconitos.
Tampoco nos vamos a liar aquí a todas las.
Tenemos el retweet y el like.
Vale, pues, vamos a buscar el hard.
¿Qué hard?
Es que tiene tantos, tío.
Es una burrada.
O sea, si no está aquí, no existe directamente.
Porque es que tiene demasiados y todo.
A veces creo que tiene demasiados.
Otra forma que podéis hacer de utilizar es directamente ponerlo aquí.
Y entonces le dais aquí al enter.
Espera, fijaos que tiene uno que es con código.
Que es como para que te guste el código.
Mira, ya verás.
Mira este icono.
Mira este icono que maravilla.
Un corazón con un código al lado.
No me digáis que no se os derrite el corazón con esto.
Porque es que es para derretiros el corazón.
¿Qué más?
¿Retweet?
Ah, arrow, div.
No, pero div, arrow, div.
Div.
Me has engañado.
Ah, pero este tampoco es.
Pero tíos, cabrones.
¿Cómo no sabéis cómo es el...?
Ah, repeat.
Muy bien.
¿Qué le ha dicho?
Muy bien.
El repeat es el que más se parece.
De hecho, diría que es este.
Muy bien, ¿eh?
Muy bien el que por fin ha encontrado el repeat.
Es que me estáis diciendo unos más random que no se parecen en nada.
El de Recycle.
No me digas, hombre, Recycle.
Hay que ver.
Pero bueno, buen intento, buen intento.
Vale.
Vamos a ponerle aquí que estos sean un poquito más pequeños.
H4, H4.
Vale.
Yo creo que con H4 ya estaría bien.
Vale, vale, vale.
¡Uy!
¡Uy!
Le he liado aquí.
Ah, porque se me ha olvidado esto.
Y esto también.
Yo creo que con el 4 ya estaría.
Estos serían botones.
Button.
Ta, ta, ta.
Por ahora ponemos así.
Que tampoco es que...
Solo para que se vea que son botones.
La idea era hacer el like y todo.
O sea que...
Vamos a ver.
Vale.
Vale.
Luego lo hacemos un poquito mejor.
Vale.
El background.
Vamos a hacer una cosa.
Vamos a poner también la sección.
Un poco...
Vamos a ver.
Esta línea.
¿Cuánto ocupa esto?
Estos son...
Bueno, estos por lo tengo que tener más grande de lo normal, ¿no?
800.
600.
Vale.
Vamos a hacer una cosa.
Vamos a ponernos aquí ya para que realmente esté haciendo lo que tiene que hacer esto.
Tendríamos que tener por un lado aquí el section, que esto va a ser section central, name, max width, 600 pixels, mx auto, ¿vale?
Por ahora, esto del out lo vamos a poner por aquí, aunque sea en un sitio que no es el correcto.
Y aquí vamos a poner...
Esta es la lista de tweets.
Vamos a crear nuestro componente post, post, list, punto tsx, export function, post, list, ¿vale?
Le pasamos aquí los post y return, ¿vale?
Todo esto lo vamos a meter aquí porque puede ser que necesitemos ponerle algún tipo de estilos a esto.
Así que post list, ¿vale?
Post, post, le pasamos los post al post list.
Esto ahora lo vamos a poner por aquí, return, esto con esto.
Y aquí dentro hacemos esto.
El postcard lo vamos a importar aquí, ¿vale?
Hay errores de typescript, lo arreglaremos después, ¿vale?
No os preocupéis.
Por ahora vamos a enfocarnos en el tema de los posts, que se vea y tal.
Y seguiremos con los likes, que es interesante.
Vale, por ahora, lo primero es que vamos a tener en esta sección, vamos a poner el borde de la derecha,
o sea, de la izquierda y la derecha, vamos a poner border white, 80 píxeles, ¿vale?
A ver si salen ahí las rayitas, ¿vale?
¿Qué pasa aquí?
Esto es min screen, esto debería ser hfull por ahora, al menos, para que veamos, ¿vale?
Porque esto, ¿qué tiene aquí?
Ah, hostia, este padding 24, claro, este padding 24 que hay por aquí, ¿vale?
Esto fuera, vamos a ver, hfull, min hscreen,
min hscreen, a ver, que al final esto luego lo arreglaremos, ¿eh?
Luego, lo que son las cards, las cards del postcard, le vamos a quitar el fondo,
para que quede más como Twitter, ¿vale?
Entonces vamos a quitarle el fondo que tienen.
A ver, yo me imagino que sí, ¿no?
O sea, si pones bg transparent, vamos a quitar el max width.
Yo creo que sí.
Ah, vale, vale.
Vamos a poner border transparent también.
Lo malo, claro, me imagino que tendrá un no border o algo así, a ver.
Borderless o algo.
Border, no.
No border, no.
No.
Border, a lo mejor es que este border transparent no es así, ¿no?
Border, no, transparent.
O sea, o es el shadow.
Es que a lo mejor es un shadow esto, tío.
¿Qué es esto?
Online, no.
Es un shadow, es un shadow.
Así que shadow none, ¿vale?
Para que quede un poco más, ¿vale?
Y en la página esta que teníamos el page, teníamos aquí el border wide.
Vamos a ponerlo a 50%, no, 30% para que quede más como el de Twitter.
¿Vale?
Muy bien.
Ah, y cuando te pones encima hace este hover súper chulo.
Bueno, eso lo podemos hacer un momento, ¿eh?
Hover, VG.
Vamos a poner así.
Transition.
Yo creo que el transition ya está hecho, pero bueno.
¿Vale?
A ver, cuando esto tiene que todos tienen abajo un borde.
Así que aquí vamos a poner border bottom, border wide y con el 20% también.
Vamos a ver cómo va quedando el tema.
Hostia, hostia, me he pasado con este.
Hostia, es que esto no era así, esto era al revés.
¿Vale?
Border bottom.
Hostia, pero el border no...
Transition.
Ah, es que es border B.
Cierto.
Rounded none.
¿Vale?
Y ya empieza a aparecerse un poquito más, ¿no?
Cursor, pointer, porque esto luego haremos que vaya a cada enlace.
¿Vale?
Textsmall, xs.
Al menos ya tenemos ahí los dos tweets, un poquito, que se parezca un poquito, ¿no?
Un divide, y es mejor.
Hay que recompilar.
Ah, hay que recompilar.
¿Sí?
Hostia, pues ha recompilado esto de golpe.
Porque fíjate que ha petado, ha petado, no sé por qué, en cuanto he vuelto, ha petado la leche.
Vale.
Hostia, esto es al 100%.
No me...
Muy pequeñito, ¿no?
Como muy, muy, muy pequeñito.
Pero bueno.
No sé si ponerle un poquito más.
Vamos a ponerle un poco más para que quede un poquito más grande, ¿vale?
Pero sí, ahora sí que se parece que es más grande.
Vamos a hacer una cosa muy interesante de Supabase, y luego hago lo de escribir el tweet, para que podamos escribir tweets, porque si no, no sirve esto de mucho.
Lo que vamos a hacer aquí es generar los tipos.
Esto es una cosa muy chula que tiene Supabase, que tiene un montón de ORMs y tal.
Pero con Supabase podéis crear...
Mira, podéis iros aquí, a la terminal.
Mira, vamos a abrir una nueva terminal.
Aquí.
Vamos a hacer esto un poquito más pequeño.
Y hacemos login de Supabase.
Esto lo que nos va a pedir es que tengamos un token.
El token lo tenemos que crear en la página de Supabase.
Lo creamos en un minuto.
¿Vale?
¿Ves?
Tienes que generar un access token.
Vamos aquí, a la página.
Y le damos aquí, generate token.
¿Vale?
Y le ponemos aquí, terminal login.
¿Vale?
Cuando le dé a generate token, va a salir el token.
No quiero que lo veáis, porque si no, me podéis joder vivo.
Entonces, vamos a intentar evitar que haya sustos.
No queremos sustos de ningún tipo.
Ya vemos por aquí.
Y le damos al enter.
Ya he puesto el token.
Ya he hecho el login.
Y ahora que ya hemos hecho esto, magia.
Podemos utilizar el comando npx Supabase gen de generar tipos de TypeScript.
Le decimos el proyecto sobre el que queremos generar los tipos.
Así que vamos aquí, a todos los proyectos.
Nos vamos a adapter.
Buscamos en settings.
Y en este reference ID, copiamos.
Esta es la ID de nuestro proyecto.
Lo copiamos aquí.
Le damos a enter.
Y...
¡Tachán!
Nos ha generado todos los tipos de toda la base de datos.
Imagínate.
Users, avatar URL, created at.
¿Vale?
Y ya tenemos aquí toda la información cuando queramos seleccionar, insertar o lo que sea.
Esto lo podéis copiar a mano.
Pero bueno, otra cosa que podemos hacer.
Aquí vamos a crear en app.
Vamos a crear una carpeta types.
Y aquí le decimos que nos genere los tipos en punto barra source app types database punto ts.
¿Vale?
A ver si esto debería funcionar.
Si no me he equivocado.
Y ahora en los tipos, tenemos aquí ya los tipos del database y todo esto.
Me está diciendo que unos errores del inter, sin problemas.
Y estos tipos los podéis generar cuando queráis.
De hecho, ya que hemos hecho este pedazo de comando, vamos al package.json.
Y aquí vamos a poner generate types.
¿Vale?
O gen types.
Más fácil.
Más rápido.
¿Vale?
Ya teníamos esto.
Ahora, lo bueno es que, fijaos que uno de los problemas que habíamos tenido antes, cuando estaba haciendo la página, que estaba diciendo,
ay, pero no sé si esto, si justamente, si tiene este campo aquí, este campo acá.
Bueno, como estamos utilizando TypeScript, lo bueno que tenemos es que aquí en el Create Server Component, tú le puedes decir cuál es la base de datos, cómo está tipada.
Y aquí en database lo podemos importar, ¿ves?
Del types database que hemos creado ahora mismo.
Ahora, lo bueno es que, fíjate que ya tenemos toda la información de todos los posts.
Esto no lo teníamos antes, automáticamente.
Así que, cuando aquí en post se los estamos pasando, en realidad, ahora sí que tenemos la información de los posts cuando se lo pasamos.
Lo malo aquí en el post list es que aquí no la tenemos.
Igualmente, lo que podemos hacer, si os fijáis aquí en los tipos, fíjate que los tipos tenemos interface, database, public, tables, post.
Pues, muy fácil.
Una cosa que podemos hacer sería importar el type de database, ¿vale?
Y podríamos crear el tipo posts aquí.
Porque el tipo post, si no recuerdo mal, esto se podría...
Es que, claro, hace tiempo que no hago esto.
Pero, o era así.
Ah, sí, es así.
Vale, public.
O sea, tenemos que entrar a public, tables, ¿no?
Y, entonces, así podemos extraer post, podemos extraer los tipos row.
Ya teníamos el content, no sé qué, ¿vale?
Pues, ponemos aquí row, row, y ya tendríamos los tipos del tipo post.
Así que, ahora ya podíamos decirle que esto es un array de post.
Y, al menos, así ya tendríamos esto.
Pero, claro, es verdad que, aún así, fijaos que nos faltaría, en realidad, la relación.
Porque aquí sí que tenemos la relación, pero nos faltaría la relación de los usuarios.
Otra cosa que podemos hacer es, estos tipos, tenerlos aquí separados, ¿no?
Por ejemplo, podemos tener los post.ts.
Los separamos aquí.
Utilizamos el import este maravilloso que hemos hecho.
Y aquí sí, pues, podéis hacer esto de poner los posts.
Y, además, que esto tenga, pues, users y que el users...
De hecho, post type...
Podemos sacar esto primero, ¿no?
Type, post...
No, user type, ¿vale?
User type.
Database, public, no sé qué.
Users row, ¿vale?
Y aquí lo que podemos decir, que el tipo post, pues, va a tener, es el post type.
Y, además, debería tener el user, que es el user type.
Y, con esto, deberíamos...
Ay, no, pero la unión era así, ¿no?
A ver, que alguien me lo diga.
Before, let, movie...
Tables, movies...
Ah, porque puedes traer el tables.
A ver, tables...
Bueno, al final, esto como está generado, post entity.
Me ha gustado.
Tienes razón.
Me gusta más, post entity.
Me gusta, ¿eh?
Me gusta, post entity.
Tienes toda razón.
Post entity.
Post entity y el user entity, ¿vale?
Y, ahora, aquí, pues, ya sí que podríamos traernos el import type post.
Porque el post ahora sí que es el que estamos exportando.
Los otros lo dejamos más de forma interna, ¿vale?
Lo traemos de app, types, post, post y tal.
Y, ya tendríamos aquí nuestros post.
Y, ahora, sí que tendríamos, fíjate, con todo, no tendríamos ya que preocuparnos de esto.
Y, tendríamos el user, el created at.
O sea, ahora, sí que tenemos el autocomplete.
Que, justamente, es la gracia, ¿no?
El hecho de poder tener autocomplete.
Y, fijaos, lo fácil y lo bien que lo genera Superbase.
Es verdad que tienes que crear como esta parte aquí, como más...
Tienes que crear algo...
Porque esto está generado al final.
Y, claro, es un poco rollo.
Y tienes que crear como un proxy de leer esa parte y luego sacarlo.
Pero, bueno, aún así, está súper bien.
Porque, al final, no nos tenemos que preocupar.
Y tenemos esto súper bien y ya está.
¿Por qué tiene que poner el type para importar el tipo?
¿No funciona directamente si le importa?
Funcionaría correctamente.
Pero, fíjate, hay dos cosas.
Uno, tengo el linter que me está avisando.
Me dice, todos los imports que sean declaraciones,
que solo estén utilizando como tipos, tendrías que utilizar el import type.
Y esto es bastante interesante.
Porque así estás evitando que realmente esté trayendo información que no requieres.
Eso por un lado.
Y, por otro lado, en realidad, así te evitas que se ejecute código que a lo mejor no quieres.
Imagínate que, por lo que sea, aquí tienes un console.log.
Pues, si haces un import type, esto no lo ejecuta.
Porque solo se trata de los tipos.
Pero, si haces un import normal, sí que lo ejecuta.
Así que, así tienes cuidado.
Bueno, aunque sea, aunque depende del tree shaking, ¿eh?
Depende del tree shaking.
También es verdad que eso depende un poco del tema.
Vale, me dice que aquí hay algo que no le gusta porque esperaba, no sé qué.
Que, claro, puede ser null.
Y el tipo null no se puede asignar, claro.
Porque también puede ser que se le pase un null aquí.
Entonces, esto tiene que ser esto.
O puede ser null.
Y si es null, pues lo tenemos que controlar.
También hay otro más.
A ver, ¿qué dice?
No son compatibles.
Porque también el user también puede ser null.
O sea, también, claro, esto es tirar del hilo.
Esto es tirar del hilo.
Esto es lo malo de...
Esto dice que también puede ser null.
O sea, que puede ser que no encuentre el usuario.
No he entendido el error.
No he entendido el error.
Bueno, no voy a perder mucho tiempo.
Me lo vais a arreglar.
Que para eso lo estamos haciendo de código abierto.
Ya hemos creado los tipos.
Vamos a hacer que pueda crear tweets, ¿vale?
El usuario.
Vamos a crear aquí.
Vamos a poner el composePost.tsx.
Esto está muy chulo porque, a ver, primero,
vamos a tener que mirar cómo es el tema de las tablas,
las políticas, porque hasta ahora en las policies
que hemos hecho aquí solo hemos visto de lectura.
Pero los posts ahora vamos a tener una que es de escritura.
Vamos a tener que hacer, tener una política que sea
authenticated users can create their own post.
O sea, sus propios posts.
No pueden crear un post en nombre de otra persona.
O sea, que importante.
No solo vamos a mirar que esté autentificada esta persona.
También vamos a asegurarnos que el user ID que vamos a crear en el post
sea el mismo que en la autentificación tengamos en el UID.
Esto es una función que tenemos aquí que lo que nos da es la ID del usuario
que está autentificado.
Esto porque hemos puesto aquí que los roles sean los de autentificación.
Entonces, claro, lo que hacemos es, oye, el campo user ID de lo que estamos insertando,
que es justamente si miramos en la tabla, si miramos en la tabla de los posts, ¿vale?
Ves que tenemos aquí este user ID.
Pues lo que estamos revisando es que este user ID tiene que ser el mismo
que el user ID del usuario que está autentificado.
¿Por qué?
Porque si tú pones esto, esto lo que significa es que un usuario autentificado
podría crear tweets en nombre de cualquier persona.
O sea, te podrías hacer pasar por Elon Musk y crear tweets.
Y no, lo que queremos es que solo pueda crear los suyos propios.
Igual luego cuando los queramos modificar y todo esto.
Así que nada, hacemos de esto review, insert, ¿vale?
Autentificado, creamos esta nueva política.
Ya tenemos una nueva política y ahora nos vamos a nuestro componente.
Vamos a crear aquí primero la función composePost, ¿vale?
Que le vamos a pasar el username, el user full name,
porque vamos a crear el formulario que sale arriba.
O sea, que necesitamos en realidad user avatar URL, ¿vale?
Y esto es username, es un string.
User avatar URL es un string.
Export function, ¿vale?
Por aquí.
Vale.
Entonces, ¿qué hacemos aquí?
Vamos a probar una funcionalidad bastante interesante que no he probado nunca.
O sea, que puede salir todo mal de Next.js.
Que es esta de server actions, ¿vale?
Esto de server actions tiene muy buena pinta.
Y de lo que trata es que tú puedes tener un componente y al formulario le pasas una action
que solo se va a ejecutar en el servidor, ¿vale?
Y es interesante porque justamente esto también lo soporta Superbase.
En la nueva versión esta que han sacado, aquí, si vamos a los server actions,
fijaos que aquí, además tenéis un vídeo muy interesante, ¿ves?
Te dice, mira, tienes que importar las cookies, tienes que crear server components.
Lo que vamos a hacer aquí es el hecho de, vamos a poder tener un componente que se renderiza en el servidor
y, además, lo que hacemos es crear un método que se ejecuta en el servidor.
O sea, esto nada va a estar en el cliente.
O sea, va a ser todo en el servidor.
Y fíjate que ya te lo dice aquí, use server.
Esto está en alfa, o sea, todavía está un poco verde.
Tened cuidado por ello, ¿vale?
Porque está un poquito verde.
Pero tiene muy buena pinta porque te simplifica un montón el cómo manejar el tema de acciones con formularios.
Lo que sí que es cierto es que esto mucha gente lo ve polémico
porque está mezclando servidor, cliente, no sé qué.
Y se parece un poco a lo que hacía Remix.
Pero bueno, fíjate que ya tenemos aquí el createServerActionClient.
Esto lo vamos a tener que crear para tener el cliente de su pavase en el server action.
Así que también tenemos que importar las cookies desde next barra headers, ¿vale?
Esto lo podemos hacer porque es un React Server Component, si no, no lo podríamos hacer.
Bueno, este revalidatePath me lo voy a traer solo para que me suene, pero luego lo comento.
Luego os comento porque es necesario.
Vamos a renderizar aquí.
Return, un formulario, ¿vale?
Y en el formulario le voy a poner un poquito de estilos.
Tampoco nada del otro mundo, ¿vale?
Que se ponga así.
FlexCall.
Gap.
Que tenga un poquito de espacio.
Vamos a poner el textarea.
Que aquí vamos a tener el post con cuatro rows.
Cuatro rows significa que va a tener cuatro filas que va a poder escribir.
Vamos a poner className que ocupe todo el espacio.
Text2xl.
No le ponemos fondo.
Que esté rounded.
No hace falta tampoco.
VgBlack.
Aunque, bueno, ya tenemos el color de fondo.
PlayHolder le ponemos un grey 500.
Y por ahora, más o menos, ya está bien, ¿vale?
Le ponemos ahí textarea.
Muy bien.
Textarea.
Y le ponemos, eso sí, en el PlayHolder le vamos a poner el...
¿Qué está pasando?
Me da bastante rabia en Twitter que tienes esta forma que te dice
¿Qué está pasando?
Como, escríbeme, dime algo, haz algo, muévete.
Yo qué sé.
Vale.
Postear.
ClassName.
Vamos a poner VgSky300.
FontVault.
Rounded.
Full.
Px5.
PI2.
Esto es el botón, ¿vale?
Esto lo vamos a poner en el flex.
No.
SelfN para que quede en el fondo, abajo a la derecha.
Y yo creo que ya está, ¿no?
Mira, voy a poner esto.
Vale.
Vamos a poner esto en un dip porque también tenemos...
Y este flex me lo voy a copiar aquí.
Porque también tenemos que poner el avatar.
Así que avatar.
De hecho, me voy a copiar el avatar que habíamos hecho aquí.
Este.
Este.
Me lo voy a copiar aquí.
Pam, pam, pam.
Radius Full Size.
No sé qué.
Y este UserAvatar URL.
Vamos a ponerlo por acá.
Y este Username.
¿Para qué queremos el Username este?
En realidad no es necesario el Username como tal.
O sea, solo con el avatar del usuario atendíamos.
Esto sería un poco lo visual, ¿vale?
Y esto ahora haremos la funcionalidad.
Vamos a poner el Page.
Aquí teníamos el Compose Post.
Que es lo que hemos creado.
El OutButtonServer.
Lo vamos a sacar de aquí.
Lo vamos a poner debajo de los posts.
¿Vale?
Y aquí nos faltaría el UserAvatar.
Vale.
El UserAvatar lo vamos a sacar de su pavés.
Entonces, no sé si sacarlo.
¿Sabes?
No sé si traérmelo de aquí.
Ah, bueno, sí.
Porque en la sesión ya tenemos el usuario.
Vale.
Pues mira.
Compose Post.
User.
Avatar URL.
Sesión.
User.
Metadata.
¿Vale?
Y avatar.
Vale.
Aquí no sale, pero creo que es Avatar URL.
Esto lo hemos visto antes.
O sea, esto lo sacamos de la sesión que tener, debería tener.
Porque si no, tiene sesión.
O sea, este Optimal Chaining sobra.
Todo lo demás debería estar bien.
Entonces, con esto ya teníamos el UserAvatar.
¿Vale?
Vamos a ver cómo se ve.
Si es que se ve.
Vale.
No se ve.
Dice, vale.
Dice, estás importando un componente que necesita un UseEffect.
Y esto solo funciona en componentes de cliente.
Ostras, esto me está dando problemas en NextUI.
Pero esto de NextUI no tiene sentido que me dé problemas porque se supone que por dentro estos componentes, o sea, este componente avatar, a ver, lo voy a dejar de usar porque me parece un poco raro.
Pero internamente debería utilizar el UseClient y no debería tener este problema.
Raro.
Raro, raro, ¿eh?
La verdad, raro.
No sé.
Me parece extraño.
No sé.
Vamos a poner 6H6 y ObjectContain.
¿Vale?
A ver si ese es el problema.
Sí, ese es el problema.
¿Vale?
¿Qué está pasando?
Joder, este postear es enorme.
¿Qué pasa con ese postear?
¿Dónde he puesto?
Hostia, es que he puesto aquí un XL.
TXL.
Hostia, pero ¿por qué es tan grande este postear?
Vamos a ponerle más fuerte, menos fuerte, algo así.
Y no sé, no sé por qué ha salido eso tan fuerte.
O sea, ¿por qué sale tan grande?
¿Ves?
Es que está mal.
Hay algo aquí rarísimo.
290.
Pero aquí pone Max 800 y tal.
Max Width 800.
Es que esto puede ser que no tenga el Width al 100%.
Claro, es que ese es el problema.
Ya decía yo que lo veía como muy pequeño, muy chico.
Y digo, ostras, es que, claro, es que el tema es que cuando hemos puesto esto, aquí se nos ha olvidado poner que ocupe todo el ancho.
Que sí, que está bien que tenga un máximo, pero no tiene sentido si no ocupa todo el ancho.
Claro, ahora este es el ancho realmente que tiene Twitter.
Ahora nos damos cuenta de exactamente cómo están los anchos y tal.
En el avatar lo hacemos más grande, que yo creo que será mejor un 12, algo así.
Esto hacemos que sea flex y hacemos que sea flex row por defecto, ¿vale?
Para que esté uno al lado del otro.
Le ponemos un space x de 4, ¿vale?
Para que esté ahí separado.
Vamos a ver cómo es exactamente esto.
A ver aquí, ¿qué está pasando?
Bueno, más o menos, ¿eh?
Más o menos.
Vamos a ponerle un poco de padding a este.
Vamos a ponerle padding 4, ¿vale?
Y ahora ya está un poquito mejor, ¿vale?
Y ahí tenemos el postear, ¿qué está pasando?
También el textarea este.
Debería tener un padding 4, vamos a poner.
Padding 2.
Igual nos hemos pasado con el padding.
Y ahora ya, pues ya estaría un poquito mejor.
Que justamente está mejor alineado a como es aquí, ¿no?
¿Qué está pasando?
Ah, el border bottom.
Tienes toda razón.
Me ha faltado ahí el border bottom.
Border bottom.
Border B.
Border bottom.
Border bottom.
Bueno, border white.
Creo que era 20, si no me equivoco.
Y ya tendríamos ahí.
Muy bien, muy bien.
Gracias, gracias, ¿eh?
No está mal, no está mal.
Vale.
Nos faltaría alinear esto.
Lo alineamos después, ¿vale?
Porque fijaos que esto no está del todo alineado.
Y debería estar alineado, fijaos.
También es porque tendrían que ser del mismo tamaño.
A ver, ¿cuál es el tamaño exactamente?
Es que no quería hacerlo pixel perfect, tampoco.
40, 40.
Vale.
¿Y este cuánto es?
Esto es 48, 48.
O sea, que en realidad esto es 10.
Vale, pues por ahí iría un poco la cosa.
Y ahora lo que faltaría es el padding, porque el padding no es exactamente el mismo.
Pero bueno, que ya os digo que no quiero que sea exactamente pixel perfect.
Que la idea es un poco que quede más o menos igual y luego ya lo moveremos.
Ahora lo que nos faltaría es, bueno, y cómo hacemos que al darle a postear realmente esto haga lo que tiene que hacer.
Vamos a asegurarnos que el botón este sea del tipo submit, ¿vale?
Que en realidad cualquier botón que esté al final dentro de un formulario va a hacer el submit.
Y aquí normalmente se hace, cuando se hace submit, tal.
Bueno, pues vamos a ver las server actions que están en alfa, ¿vale?
Vamos a hacer aquí action y vamos a poner aquí add post.
Creamos un add post aquí, que tiene que ser un método asíncrono.
Y aquí va a recibir el form data, o sea, todos los datos del formulario, ¿vale?
Lo tipamos con el form data y aquí pues podemos poner un console.log si queremos.
Hola mundo, para asegurarnos si esto funciona o no funciona.
Y por ahora con esto tendríamos, ¿vale?
Aquí tenemos ya un error que dice, functions cannot be passed directly to client components unless you explicitly exposed marking by with use server.
Y es que esta función no se le puede pasar a un formulario como si nada,
sino que tenemos que crear aquí una cadena de texto especial que se llama use server.
Que lo que está indicando es que este método solo se ejecuta en el servidor.
Y ahora con esto, otro problema.
Y es que el problema es que, fíjate, los server actions hay que activarlos porque están todavía en experimental.
Así que hay que ir a next.conf.js y aquí dentro de experimental tenemos que activar los server actions y esto lo ponemos en true.
¿Vale?
Y ya lo tendríamos por aquí y ahora si volvemos a mirar, esto me da mucha rabia de next.js.
Ojalá algún día lo arreglen.
Y es que a veces cuando tocas el config se cae el servidor.
Que es lo que ha pasado, ¿ves?
Fauna change y no sé qué.
Restarting server.
Restarting no, lo que me lo has tirado abajo.
¿Qué restarting?
Me lo has tirado abajo.
O sea, no me has dado, vamos, ni posibilidades.
¿Por qué usa use server si suave sirve en el cliente?
Bueno, pero porque no es un tanto de por qué sirva en el cliente, es un tema más de no tener que enviar este JavaScript al cliente.
Hostia, porque ahora tiene más padding esto, ¿sabes?
O sea, ¿qué ha pasado aquí?
Ah, ajá.
Este input, este image.
O sea, tiene como...
¿Pero por qué tiene esa separación?
¿Sabes?
O sea, no entiendo por qué esa separación.
¿Sabes?
O sea, porque tiene un margen.
Ah, tiene un margen.
¡Qué cabrón!
Es por ese input hidden.
Hostia.
¿Sabes?
O sea, estaba pensando por qué pasa eso.
Y es por el SpaceX este.
Es por culpa de esto.
Y es por culpa de esto porque ese input hidden que está metiendo Vercell...
Hostia, pues esto es bastante peligroso, ¿eh?
O sea, estaría bien que no fuese necesario.
Pero por culpa de este input, como es un input y al final no tiene un display known, el problema es que se cree que es un elemento dentro del flex y, por lo tanto, está ocupando un espacio.
Claro, es que por eso no entendía por qué la imagen al lado tenía esa separación.
Y es justamente por eso.
Curioso, ¿eh?
Pues, pues no sé.
Podríamos ponerlo aquí.
A ver, al final tampoco es muy importante donde esté...
Lo importante es que esté bien separado.
¿Y el SpaceX lo he quitado?
Ah, no, es que no lo he quitado.
Vale, pues esto lo ponemos aquí.
Esto lo ponemos acá.
Y al menos ya un poquito mejor.
Claro, lo que nos faltaría...
Claro, como he tocado el padding.
Esto es padding 4.
Vale, y ya está.
Igual le he puesto padding 3 al otro, ¿verdad?
Porque esto debería estar ahora alineado.
Sí, ahora sí que está alineado.
¿Qué está pasando?
¿Qué está pasando?
Bueno, pues ahora cuando yo aquí hago a...
Y le doy a postear, parece que no ha pasado nada.
Pero si me voy a la terminal, ¿vale?
¿Ves que pone aquí hola mundo?
Bueno, pues es que resulta que se está ejecutando esto.
¿Ves?
Hola mundo.
Esto significa que esta función funciona, que es su objetivo.
Así que ahora lo que vamos a hacer es, primero, vamos a recuperar el contenido utilizando el formdata.
Hacemos el get del content, ¿vale?
Y este content de dónde...
Ah, del post, no del content.
Le he llamado...
Bueno, depende.
Le podemos cambiar el nombre.
¿Ves que aquí en name le he puesto post?
Le puedes poner content y todos están contentos, ¿vale?
Y así recuperamos el contenido.
Y aquí ahora, si tenemos contenido, ¿vale?
Si el contenido es diferente a null, porque el formdata, si no encuentra el contenido,
esto puede volver null y hay que chequearlo.
¿Veis ahí que pone que puede ser null?
Entonces, tenemos que revisarlo.
Si es diferente a null o es diferente...
O sea, aquí podríamos revisar o podríamos mirar, por ejemplo.
Lo hacemos mejor al revés, ¿no?
No sé si hacerlo...
¿Sabes?
O sea, si el contenido es null, hacemos un reto.
Ya está.
Punto.
Y así ya no hace falta continuar.
Y ahora creamos el cliente de Supabase.
Create server action client.
Le pasamos otra vez las cookies, ¿vale?
De esto, ahora vamos a hacer Supabase.insert...
No.
¿Insert?
Espérate.
From.
Exacto.
Muy bien.
Gracias.
Aquí podríamos hacer un chequeo antes de hacer esto.
O sea, aquí podríamos revisar si el usuario realmente está autentificado.
¿Sabes?
O sea, aquí podríamos mirar...
Podríamos mirar...
Podríamos recuperar la sesión, ¿no?
Const data user await Supabase punto out get user.
¿Vale?
Podríamos mirar esto en el caso de que este componente lo vayamos a utilizar en más sitios
aparte del actual, que es la home.
Claro, en la home, como ya estamos reireccionando, esto no sería necesario.
Pero puede ser interesante si user es igual a nul, pues nada, return también otra vez.
Y así evitamos ya insertar esto con algún problema.
Claro, en realidad también es importante porque le tenemos que pasar el user ID.
Claro, le tendríamos que pasar el user ID.
Así que no, no, es importante.
Porque los inserts de los posts, para que nosotros le sepamos esa relación,
le hemos dicho a nosotros que le vamos a pasar el user ID.
Sí que se podría, se podría llegar a hacer con un trigger, pero bueno, en este caso
tampoco me parece que sea necesario.
Podemos recuperar el usuario porque ya hay una política que no vas a poder pasarle aquí
lo que te dé la gana.
¿Sabes?
Sí, lo que te dé la gana.
Aquí solo le puedes pasar tu user ID.
Y si el user ID es el mismo del autentificado, entonces sí que guardará el post.
Si no, no lo guardará.
Así que ya tiene sentido.
Claro, tiene sentido.
Recuperemos el usuario.
Veamos que si no tengo usuario, hacemos un return porque no vamos a poder insertar esto.
Y finalmente le pasemos el user ID.
No necesitamos pasarle el cruitedad ni otra información porque realmente esa información
ya tiene valores por defecto.
Y ya está.
Con esto ya tendríamos al menos el insert.
Yo creo que esto debería funcionar.
Lo que pasa, a ver, si le vamos a postear.
A ver, vamos a postear.
Y le damos a postear.
Vale, parece que no pasa nada, pero si refresco, ¿vale?
Fíjate, lo tenemos ahí.
Lo que podríamos hacer aquí es lo que habíamos visto aquí.
Creo, aquí tengo dudas, creo que esto de Revalidate Path, si revalidamos el path,
debería pasar un poco similar a lo que hemos hecho antes con el refresh.
O sea, lo que debería pasar aquí es que si le indicamos el path que queremos revalidar,
debería volver a preguntar por la información.
O sea, aquí deberíamos ver que ahora que revalidamos esa ruta,
va a volver a hacer toda la petición de todos los server components y tal,
va a hacer todos los fetch automáticamente sin estado ni nada,
y entonces deberíamos volver a ver el nuevo.
Vamos a probar, vamos a probar.
¿Ves?
Y lo que está chulo es que fíjate que no hemos tenido que hacer nada, ¿sabes?
O sea, no hemos tenido que guardar un estado, un useEffect,
no hemos tenido que hacer absolutamente nada, ni un nada.
Simplemente lo que estamos diciendo es,
oye, cuando termines de insertar esto, me tienes que revalidar el path,
la ruta, que es barra.
¿Y qué es lo que va a ocurrir?
Lo que ocurre en este punto es que NextYes le da un mensaje a la ruta y le dice,
vale, vuelve a entrar aquí al page, a esta ruta, ¿no? A este page.
Me ejecutas de nuevo esto, me ejecutas de nuevo esto,
me ejecutas de nuevo esto y me vuelves a renderizar todo lo que hay aquí.
Y en el cliente, solo aquello que tiene un cambio, me lo machacas.
O sea, realmente me reconcilias lo antiguo con lo nuevo.
Por eso es súper interesante que si hacemos cosas aquí, no ves...
Mira, si hacemos cosas aquí, fíjate, en la red, ¿vale?
Le voy a dar a postear y...
Vale, han pasado dos cosas.
Es que, claro, me sabe mal porque estaba en JavaScript,
pero han pasado dos cosas.
Una, este localhost que ha hecho un post,
que le está enviando el contenido, este es el server action, ¿vale?
Y en el server action ya directamente es que, como puedes ver,
ya nos ha revalidado toda la información
y no hemos necesitado hacer absolutamente nada.
No es que ha hecho un refresh, no ha hecho absolutamente nada.
Simplemente estamos aprovechando,
revalidando el path con la información
y diciendo, vale, pues ya está.
Con esta información vamos a volver a pedir todos estos datos
y vamos a revalidar en el cliente solo los cambios que tengan sentido.
Ni un parpadeo, con muy poco código, sin tener que preocuparse.
La verdad es que la experiencia de desarrollo del usuario está súper bien, ¿eh?
Con esto ya tendríamos esta maravilla, ¿eh?
Que no está mal.
El revalidate path es de Next, efectivamente, ¿eh?
Este revalidate path que hemos hecho, utilizado aquí,
esto es de Next.
Es lo que, de hecho, lo estamos sacando de Next caché,
para que te hagas la idea.
Bueno, pues ya estaríamos aquí, estaríamos insertando tweets.
Hay que limpiar el formulario a postear.
Hay que limpiar el formulario a postear, tienes toda razón.
Y, sinceramente, tengo dudas de cómo lo podríamos hacer.
¿Qué pasa?
Que esto es un componente del servidor.
Entonces, no sé cómo lo podríamos resetear.
¿Por qué?
Porque, como no es...
A ver, lo podríamos mover a uno del cliente,
que sería un poco rollo, pero no me gustaría.
Y la verdad es que no he visto ningún ejemplo
de que realmente, en algún momento, limpien el formulario.
¿Veis?
Lo de revalidate, custom, ta, ta, ta...
Se me ocurre que podríamos utilizar el form status,
porque el use form status, este,
nos indica si está en pending y tal,
y este lo podríamos cambiar.
Que los posts salgan del más recién al más antiguo.
Bueno, eso lo podríamos hacer aquí, en el order.
Así.
¿Vale?
Que esto lo...
Si hacemos cosas aquí...
Vale, ya lo tendríamos así.
¿Qué podríamos hacer?
A ver, una cosa que se me ocurre que podríamos hacer,
es que este textarea, lo tengamos en un componente...
Lo voy a probar, ¿vale?
No se me ha ocurrido cómo lo podríamos hacer,
con post, post, textarea.
Claro, tened en cuenta que tenemos que separar esto, ¿sabes?
Esto es un React Server Component,
y por lo tanto, no podemos acceder al elemento del DOM,
no podemos hacer un montón de cosas.
Podríamos intentar acceder, o sea,
separar lo que es el textarea,
con post, textarea,
por ejemplo, textarea,
return, ¿vale?
Esta parte, separarla, total.
Esto tiene el nombre aquí, no hay ningún problema.
Y aquí podremos utilizar lo que parece esto,
el useFormStatus,
useFormStatus, que es experimental también.
Claro, es que los server actions todavía están un poco verdes.
Entonces, con el useFormStatus,
aquí tenemos el pending.
El pending.
¿Qué pasa?
Vamos a tener una referencia.
Vamos a traer el useRef.
A ver, esto es como se me ocurre, ¿eh?
Seguramente habrá otra forma.
Send, submit.
Seguramente habrá otra forma,
pero no se me ocurre.
Y esto, en el useEffect,
vamos a hacer que cada vez que cambie el pending,
vamos a...
Si está pending al ready,
vamos a poner al ready send.
¿Vale?
No.
Esto no es lo que queremos.
Esto no es lo que queremos,
pero bueno.
Vamos a poner textAreaRef,
useRef, null.
Y esto que queremos guardar aquí
va a ser un HTML textArea.
¿Vale?
Esto lo ponemos aquí
para tener la referencia.
Y en lugar de hacer esto,
lo que vamos a querer,
textAreaRef,
textAreaRef.
current.reset.
No, no tiene reset, ¿no?
O sea, value.
La parte...
Sí, la parte izquierda no...
Entonces, si está pending...
No, si el pending...
Si el pending...
¿Qué estoy pensando?
A ver.
Si de nuevo ya se ha enviado,
si esto es true,
entonces...
already send...
already...
Si cambia el pending
y es total,
entonces le cambiamos esto
y si estaba pending,
entonces significaba...
No, ¿qué está pasando?
No, esto no es.
¿Qué está pasando?
No.
A ver,
lo que estoy pensando es básicamente
ya estaba pending una vez,
¿sabes?
O sea, que lo que podemos hacer
es darle la vuelta.
El pending al principio
obviamente está en false,
pero cuando se cambia
el pending
a false,
si el pending es false
y el recent current
esto
es en true,
o sea, ya se había enviado
en lugar de utilizarlo,
entonces lo que hacemos es
esto lo pasamos a false
y entonces el textAreaRef,
el current,
se lo ponemos
al...
Ah, sí, ¿vale?
Es posiblemente null.
Sí, ya lo sé que es posiblemente null.
¿Veis por qué es súper importante
que tengamos esto ya?
Por eso,
porque si no hay que poner aquí
también otra vez
if, text, area,
hacer este tipo de...
Venga, sí, toma,
ya está,
deja de molestarme.
Vale,
si no es pending
pero ya se envió,
entonces tal,
¿vale?
Esto hacemos un return
y si no,
vamos a hacer que el
ready,
send,
current,
sea pending.
¿Vale?
y ya está.
Con esto,
no sé,
no sé si funcionará,
vamos a probar.
Vamos a probar,
a ver si cuela.
A ver si proba.
Es la primera vez
que me peleo con los...
Vamos a probar,
postear.
Vale,
no lo ha hecho.
No lo ha hecho
y vamos a ver
qué es lo que tiene el...
Ah,
no lo ha hecho.
Si es que tampoco lo he usado,
yo también.
Si no uso los componentes
que hago,
pues,
¿cómo va a funcionar la cosa?
Así es normal
que no funcione.
Bueno,
igualmente voy a poner aquí
unos console logs bonicos
para ver el pending,
pending,
¿vale?
Y aquí vamos a ver
el console log
para ver el
already sent,
¿vale?
Muy bien.
Venga,
vamos a ver ahora.
Vamos a probar,
probando,
postear.
¿Eh?
¿Qué ha pasado?
¿Qué ha pasado?
Bueno,
ha funcionado,
ha funcionado.
Ha funcionado,
obviamente no es lo mejor del mundo,
¿vale?
No es lo mejor del mundo,
pero ha funcionado.
¿Por qué ha funcionado?
A ver,
estoy como trampeando
alguna cosilla aquí.
Lo que estoy haciendo es,
oye,
si te pones en pending,
significa que lo has enviado,
o sea,
lo estás enviando.
Si alguna vez has estado en pending
y de repente
dejas de estar pending,
es que al final
sí que has podido funcionar,
¿no?
¿Pero qué pasa si hay un error
en la función del servidor
y no se guarda la info?
Buena pregunta.
Pues en ese caso,
la verdad,
es que es una pena
porque en el form status este
es que no hay información,
¿no?
¿Ves?
Solo tienes action,
data,
method.
Entonces,
claro,
no podemos tener
la información
de si ha habido un error,
¿no?
Así que es una pena
porque en este caso
lo va a petar.
Yo me imagino,
pensar que está en alfa,
yo me imagino
que en este use form status
o aquí
vamos a tener una forma
de realmente hacer esto
en condiciones
sin necesidad
de pasar esto
a que tengas
de ser un component client.
Si no,
podría pasar esto
a un component client
pero es que,
claro,
perdemos un poco
unas cuantas cosas
de lo que estamos haciendo.
Otra cosa que podríamos hacer
es guardar esto
en el local store,
que no sé qué,
no sé cuánto.
Si el formulario es de tipo cliente,
¿el action podría seguir
siendo del tipo servidor?
Sí,
podría ser.
Podríamos hacer el componente
de tipo cliente
y podría ser todavía
del tipo servidor.
No habría ningún tipo
de problema,
¿sabes?
O sea,
podríamos pasar aquí
use client.
El problema del use client
que nos complicaría
este cookies.
Entonces,
este cookie
debería,
dejaría de funcionar
y tendríamos que separar
unas cuantas cosas.
Y me da un poco de palo
tener que separarlo o tal.
Pero bueno,
pensad que está en alfa.
O sea,
las server actions
están en alfa
y que por eso seguramente
todavía le faltan
algunas cosillas.
Por ejemplo,
como el hecho este
de limpiar.
Yo creo que eso
lo simplificarán,
lo mejorarán.
O yo no he visto un ejemplo.
A lo mejor sí que...
Por ejemplo,
¿para qué está chulo
esto del pending?
Esto del pending está chulo
porque realmente
el pending este
lo puedes utilizar
para que el botón
cambie esto.
Este botón
lo podríamos poner aquí
con post text button.
¿Vale?
Esto lo pones aquí
con post post button
tsx export function
post post button.
Y lo que está chulo
de esto,
y esto sí que funcionaría,
es el hecho de que
cuando tú tienes
este estado de pending
está chulo,
pero es verdad
que tenéis razón.
O sea,
nos falta saber
si ha habido un error.
Pero es que no hay forma.
O sea,
no hay forma fácil
al menos de...
No hay ni un ejemplo
que te dé una idea.
Se me ocurren cosas
muy piratas
como redireccionar,
poner en un query param,
revalidar otra vez la...
Pero claro,
me parecen como
demasiado bestias, ¿no?
Disable.
Mientras está pending,
¿no?
Y aquí podrías poner
posteando.
O sea,
si está pending,
pending,
podríamos poner aquí
posteando
y si no,
postear.
Claro,
para esto está muy chulo
porque aquí tiene sentido,
pero es verdad
que le falta un poco
de granularidad
a la hora de saber realmente
si ha fallado,
si ha habido algún problema.
Mira,
disable opacity,
le ponemos aquí 40
y disable pointer events none
y tal.
Entonces,
ahora,
cuando posteas,
si le das a postear,
pues tampoco...
No sé si va muy rápido
y no le da tiempo.
No sé si es por la revalidación,
pero al menos no he visto esto.
A ver,
vamos a ponerlo más lento
a ver si lo vemos.
Yo ahí no he visto
el pending en ningún sitio.
Ah,
no sé.
O sea,
será por el use client,
¿no?
A lo mejor es que necesita...
Claro,
esto tiene que ser use client.
A ver ahora.
¿No?
Pues tampoco.
Pero a ver.
¡Ay!
No me puedo creer
que me ha pasado
por segunda vez.
El crear el componente
y no usarlo.
No me lo puedo creer.
No me lo puedo creer.
Ahora sí.
¿Vale?
Ahí está la gracia.
Ahí está la magia.
¿Habéis visto la magia?
La magia.
La magia,
¿no?
Que sale ahí posteando y tal.
Eso está súper chulo,
¿eh?
Pero sí que está refrescando
la página.
Refrescando.
No está refrescando la página.
¿Dónde ves que está
refrescando la página, amigo?
¿Dónde lo ves?
¿Dónde está refrescando?
¿Dónde está?
Que yo lo vea.
¿Dónde está?
Que yo lo vea con mi gafa.
A ver.
Cuenta los caracteres.
Puede ser.
Esto es un real medio bizarro igual.
La verdad...
La verdad es que sí.
O sea,
la verdad es que sí.
La verdad es que se está convirtiendo
en algo bastante complicado.
Bastante complicado.
Que es muy potente.
Mira,
Gonzi lo tenemos ahí.
Que está muy chulo.
Está muy,
muy chulo.
Una vez que le falta alguna cosa
a los server actions.
No sé.
Mira,
ya que tenemos a Gonzi,
que seguramente él sabe mucho más
de NextGS que yo.
Gonzi,
cuando...
Bueno,
es que ahora lo he arreglado
de una forma muy pirata
aquí con el Texaria,
con el Formstatus.
Pero tú sabes
si al tener un server action
puedes limpiar el formulario
desde el servidor.
Decirle,
oye,
límpiame el formulario
de forma fácil
porque es que no encontrar un ejemplo.
Gánate el sueldo.
Gánate el sueldo,
Gonzi.
Si importas el server action
podrás hacer ambas.
Llamar al action y limpiar.
O sea,
lo dejas todo como client.
A ver si soy capaz
de entender lo que ha dicho,
¿vale?
Pero entiendo que
hacemos un actions,
o sea,
actions aquí.
Ah,
pues eso está interesante,
¿no?
O sea,
el hecho de...
¿Ves cómo sabe este chico?
¿Cómo sabe este chico?
¿Cómo sabe este chico?
¿Cómo sabe?
O sea,
podríamos hacer así.
AdPostAction.ts
Entiendo que podríamos hacer esto.
Import cookies
from next headers.
Claro,
pero esto me va a permitir...
No sé si me va a fallar igualmente,
pero bueno,
lo probamos igual, ¿eh?
Lo probamos igual
que me parece igual divertido.
Export addCons.
Entonces,
esto lo quitamos de aquí.
Esto.
Ponemos aquí el useClient.
Este createServer.
Todo esto
no lo necesitamos.
Ya lo tenemos en...
Aquí.
Pa, pa, pa.
Aquí el addPost
lo vamos a importar.
Este useClient...
Claro,
en este...
Claro,
pero entonces,
¿en qué momento sabes
que tienes que...?
Porque aquí es donde sabes
que está bien o está mal.
¿Cómo haces
de que este sea
el...
que cuando sabes
que has hecho el insert
entonces funcione?
¿Sabes?
Ese es el tema.
Yo lo que quiero es
resetear aquí solo.
Reset aquí.
Este era.
A ver,
enhancements...
O sea,
donde tengo entendido
el transition
no se ejecuta
después de la action.
O sea,
que sería
utilizar el transition.
A ver.
Puedes invocar
several actions
sin utilizar action
o from action.
Puedes utilizarlo
utilizando esta transition.
A ver.
Pero...
Start transition.
Add item.
Pero tampoco...
Tampoco veo...
Tampoco veo aquí
realmente...
¿No?
Porque pone
add item.
Entonces,
una vez que has hecho
el add item,
¿vale?
Revalidate.
Es que hace exactamente
lo mismo.
O sea,
no veo que haga algo
justo después
del start transition.
Por ejemplo,
yo qué sé.
Es que no hay
ni un ejemplo.
La verdad es que
es muy raro
que no haya un ejemplo.
Así, ¿no?
Pero es que
esto es el
use optimistic.
Esto es para
temas optimistas,
pero esto sería
otra cosa, ¿no?
Ah,
en este caso...
Ah, vale, vale,
que veo este.
Vale, vale.
Claro,
pero este...
Add optimistic message.
Claro,
pero el add...
Esto es como para
hacer al revés,
¿vale?
Esto sería como para
hacer al revés, ¿no?
Esto sería como para
cuando tienes el mensaje,
lo añades
antes de que se vea,
que es interesante,
pero es como al revés,
¿sabes?
Es como al revés
de lo que queremos hacer.
Y realmente aquí,
claro,
este formcun reset,
que esto está chulo,
pero esto es porque
tiene el use client aquí.
O sea,
que al final...
O sea,
que tienes razón en esto,
que al final sería
hacer esto que comentas aquí,
¿no?
O sea,
tú tienes aquí
el async,
lo que pasa es que entonces
hay que cambiar alguna cosilla,
pero bueno,
pasa nada.
O sea,
sería await,
add post,
le pasas el form data,
que es justamente lo mismo
que recuperamos aquí.
Vale.
Claro,
es que como me está pasando esto
del use optimistic,
pensaba que era utilizar
el use optimistic.
Pero vale,
entiendo que era esto
lo que me querías enseñar.
Claro,
y aquí tendríamos el form ref
y tener esto.
La verdad es que es como demasiado...
Como que hay algunas cosas
que dices,
ostras,
qué chulo,
que no sé qué,
y luego de repente
algo un poco sencillillo
como esto,
pues no es tan sencillo
y es sorprendente,
¿no?
Vale,
y esto,
¿qué dice?
Que form ref,
tipo,
espera,
tipo undefined,
no se puede asignar el tipo,
vale,
null,
y form data,
vale,
entonces tú lo que dices aquí,
form ref,
current reset.
Básicamente sería hacer esto.
Que esto puede ser null,
hacemos esto,
y ya está.
O sea,
solo cuando tengamos esto,
hacer todo lo demás.
Y esto,
el addPost,
esto seguiría utilizando esto,
el revalidate todavía lo necesitaríamos.
Claro,
el revalidate path
tendríamos esto
y en el textarea,
en lugar de hacer todo esto
que yo he hecho,
que es bastante pirata,
todo lo que he hecho aquí,
esto lo volveríamos a poner
en el otro sitio.
Voy a eliminar este componente
para que veamos
que no lo estamos usando.
Lo volveríamos a poner así,
esto lo pondríamos aquí,
esto lo podríamos petar.
Vale,
no sé si el formulario
resetea los textarea,
yo me imagino que sí.
Pero vamos a ver,
me imagino que esta era un poco la idea,
¿no?
O sea,
llamar directamente dentro de esto,
claro,
lo que esto,
ah,
y aquí no hace falta poner
use server.
Vale,
recuperamos esto,
add upstream message
y luego hacer esto.
Vale,
vale,
vamos a probar.
no le gusta.
No le gusta,
ah,
pero,
claro,
no le gusta.
Claro,
es que,
es que no se puede,
no se puede,
no se puede,
no se puede.
La conclusión es no mezclar
el front y el back,
claro,
no se puede con esto.
Aquí necesito el use client
porque quiero tener acceso
al DOM
y resetear esto.
Pero resulta que el add post este,
el add post este,
justamente tengo que tener acceso
a las cookies
para crear el server action client.
Sin el server action client este
que es pasándole cookies,
no puedo crear el cliente de Superbase,
pero tengo que leer de las cookies.
Entonces resulta que entonces
no me funcionaría el add post.
Ahí tendríamos el problema
porque esto sería el servidor
y tengo que tener acceso
a las cookies
y aquí tendríamos este.
Hemos visto la forma de arreglarlo.
Yo creo que esto lo arreglarán,
es que ya os digo
que está en alfa
y por eso yo me imagino
que es un poco demasiado rebuscado.
Si no,
entonces podríamos darle la vuelta
y al final
lo que hacemos
es que esta parte
del servidor de Superbase
pues hacerlo de otra forma
y ya está.
O no utilizarlo server
y ya está.
¿Qué le vamos a hacer?
Pero ese es el problema,
básicamente.
¿Ves?
Lo de las cookies.
Este use client
pues no se lo come con patatas.
No se lo come con patatas.
¿Ves?
No puedes utilizar el use ref
porque esto sería el servidor
tampoco podrías utilizar esto
y por lo tanto
esto tampoco lo puedes utilizar
y por lo tanto
aquí lo único que puedes utilizar
es el addpost
y por lo tanto
esto es lo que hay.
Esto es lo que hay.
Bueno,
al menos hemos encontrado
una forma de arreglarlo.
Si no,
pues no utilizamos
los server estos
y ya está.
Al menos hemos visto
cómo lo podríamos arreglar.
¿Parece bonito Next.js
hasta que le pide cosas de verdad?
No,
pero pensad,
a ver,
ahora en serio,
hay que tener en cuenta una cosa.
Esto está en alfa.
Lo de server actions
lo quería probar
porque no lo había probado nunca
y, hombre,
está en alfa.
No es que esté en beta,
es que está en alfa.
Pensad que hay cosas
que cambiarán,
hay otras que las romperán
y hay otras que las arreglarán.
Y yo creo que en este caso
lo van a arreglar
porque es raro
que no puedas hacer
este tipo de cosas
o que tengas que mezclar otra vez
lo de cliente y tal.
Entonces,
es tan experimental.
Hay que tenerlo en cuenta
que esto todavía
no está 100% arreglado
y cuando lo tengan
pues veremos cómo lo solucionan.
Bueno,
claro,
lo que me decían del use server,
espérate,
que igual aquí tienen razón,
o sea,
de poner el use server aquí,
ojo,
ojo,
vamos a probarlo,
vamos a probarlo,
vamos a probarlo,
que igual tienen razón,
vamos a probarlo.
Si ponemos esto,
vamos a tirar esto para atrás
y ponemos aquí el use client
y el use server
lo ponemos a todo el action,
¿esto funciona o no funciona?
Igual funciona,
¿eh?
Igual esto funciona.
Vamos a probarlo.
Igual esto funciona.
Igual esto funciona.
Vamos a ver.
Funcionó.
Tenía razón el chico del use server arriba.
Tenías razón.
El pobre se habrá ido enfadado,
¿te imaginas?
Porque le he dicho,
no,
que no funciona así
y tenía razón.
Tenía razón.
Es verdad que aquí
lo llamé loco
y tenía toda la razón.
Tenía toda la razón.
Y ahora el pobre,
¿te puedes creer?
Explicándole a su novia.
Pues va el tío,
el gilipollas,
este novacicaso,
que no sé qué,
no sé cuánto.
No sé qué lo dijo,
pero tenía razón.
El tema,
el tema,
claro,
yo es que pensaba
que lo decía en este archivo,
no en este archivo.
Pensaba que lo decía aquí,
que lo decía aquí.
Porque como estaba aquí
con el tema del use client server,
no sé qué,
no sé cuánto,
y pensaba que lo decía aquí.
Pues sí,
es verdad,
claro,
poniendo el use server
a nivel de todo el archivo,
pues ya funciona.
Bueno,
pues ya está,
ya lo tenemos más fácil,
¿no?
Pero bueno,
hostia,
no está mal.
Igualmente nos ha costado.
O sea,
tener que resetear,
crear el ref aquí y tal,
es un poco rollo.
Estaría genial ahora
tener alguna cosa.
Pero ya está,
hemos arreglado el framework.
Lo hemos arreglado.
Y además,
mira,
lo hemos arreglado,
ahora se resetea,
aquí con el postear,
pues ha quedado de lujo.
Ha posteado,
o sea,
ha quedado de lujo.
Pues ¿sabéis qué?
Midu,
más humildad,
hazle caso al chat,
el chat sabe cosas.
A ver,
no es por nada,
no es por nada,
pero al chat le hago bastante,
bastante,
bastante caso,
¿eh?
Lo que pasa es que no me da tiempo
a leer todos los mensajes
con la carencia que me gustaría.