Lecciones del curso

Aprende Remix construyendo un Blog con MongoDB y Netlify

Clonando el proyecto
2m
Anatomía del proyecto
4m
Agregando TailwindCSS
3m
Creando y conectando con la base de datos
8m
Ruta para el login
Maquetando el dashboard
Editando posts | Primera parte
Editando posts | Segunda parte
Preparando el UI público
Redireccionando en la Página de inicio
Vista de lista
CSS para el Markdown
Blog listo para producción con Netlify
Creando Feedlinks (SSR)
Creando un sitemap.xml
Felicitación y despedida

Maquetando el dashboard

Es hora de crear una de las secciones más interesantes de este proyecto, me refiero al panel de administración.

Regularmente conocido como dashboard, aunque este nombre implicaría también la visualización de datos, el nuestro será en extremo minimalista, pero no por ello le faltará alguna funcionalidad, todo lo contrario, nuestro dashboard minimalista tendrá lo necesario para crear nuevos posts, editarlos, publicarlos o eliminarlos.

¡El CRUD completo! 🪅

Definiendo la ruta

Vamos a escribir la ruta /dash.tsx que mostrará una lista de posts de blog.

Esta ruta tiene dos funciones: mostrar una lista con todos nuestros posts; y detonar la creación de un nuevo post.

El loader entregará la lista de posts que conseguirá de la base de datos al cliente.

Mientras que el action creará un nuevo post en la base de datos y luego redireccionará a la ruta de edición utilizando el dato del post recién creado.

Habrá un botón para agregar un nuevo post, también, si damos clic a alguno, podremos editarlo en la correspondiente ruta dinámica para el detalle que crearemos en la siguiente lección.

Creamos entonces dash.ts y dibujamos el mínimo JSX para nuestro dashboard minimalista.

Con esto, estamos listos(as) para trabajar en el cliente.

Escribiendo el cliente

Nuestro dashboard consta de una barra de navegación <nav> que incluye el titulo y el call to action (el form y el botón) y también de un <section> que funciona como contenedor de todos nuestros posts, utilizando el componente <PostCard>.

// app/routes/dash.tsx import { Form } from "@remix-run/react"; import { PostCard } from "~/components/PostCard"; export default function Dash() { return ( <> <nav className="flex justify-between items-center max-w-3xl mx-auto"> <div> <h2 className="block text-3xl font-bold mt-4 px-4 text-left"> Todos tus posts </h2> <p className="px-4 text-md font-thin">Administra tu blog</p> </div> <Form method="post"> <button name="intent" value="new-post" className="text-white mr-4 bg-indigo-500 py-2 px-8 rounded-md hover:bg-indigo-600" > Crear nuevo + </button> </Form> </nav> <section className="max-w-3xl mx-auto flex flex-wrap gap-2 py-20 "> {posts.map((p) => ( <PostCard id={p.id} title={p.title} key={p.id} /> ))} </section> </>

Toma nota del <Form> de Remix que hemos incluido.

Form nos permitirá consumir el action sin refrescar la página. También nota que el botón tiene la propiedad name como intent y en la propiedad value: new-post.

Con esto estamos indicando lo que la función action debe hacer.

Leyendo PostCard

Antes de ir al backend, quiero mostrarte un componente que he creado para mostrar cada post de la lista.

import { Link } from "@remix-run/react"; export const PostCard = ({ title, id, }: { id: string; title: string | null; }) => { return ( <Link to={`${id}/edit`} className="p-4 rounded-md border border-indigo-500 w-[300px] hover:ring-indigo-500 hover:ring " > {title} </Link> ); };

Este componente devuelve un <Link> que apunta a la ruta dinámica que se encargará de la edición y que crearemos más adelante.

Escribiendo el loader

Vamos a entregar a esta ruta una lista de todos nuestros posts usando el loader.

import { type LoaderArgs } from "@remix-run/node"; export const loader = async ({ request }:LoaderArgs) => { const posts = await db.post.findMany(); return { posts }; };

Me encantan los loaders 🙈, yo utilicé Redux por varios años, incluso tengo un curso en Udemy sobre Redux, con miles de estudiantes y excelente calificación, pero cada vez que tenía que usar Redux, sufría.

El loader de Remix me devolvió las ganas de construir aplicaciones web. 😚

Gracias Remix. 🫶🏻

Escribiendo el action

Vamos ahora al action, es importante decir que en este proyecto voy a seguir un pattern que he querido experimentar:

Antes de redireccionar al usuario, quiero crear el post vacío, y con esto ahorrarme una vista, la vista de “new”, todo lo administrará una sola vista, la de “edit”.

// app/routes/dash.tsx export const action: ActionFunction = async ({ request }) => { const formData = await request.formData(); const intent = formData.get("intent"); // Usamos el intent para multiples acciones if (intent === "new-post") { // Creamos el post const post = await db.post.create({ data: { userId: "648ce85a2e43deef9f5b7a87", // @RETO Cámbia por real // Colocamos algunos defaults title: "Sin nombre", slug: slugify("sin-nombre" + Date.now()), }, }); // Redireccionamos al cliente, // usando el slug del nuevo post throw redirect(`/dash/${post.slug}/edit`); } return null; };

AUMENTAR DESCRIBIENDO EL CÓDIGO

La experiencia del usuario con este pattern me parece más que aceptable, interesante, tenía ganas de probarla. ¿tú qué opinas?

En resumen

Con la función action recibimos la petición del usuario para crear un post nuevo y lo creamos por él, con un nombre genérico, sin olvidar asignar al usuario actual como autor, para después redireccionarlo a la edición de este nuevo post. Este pattern me gusta, pues me ayuda a conseguir un dashboard minimalista. 🤓

The definition of genius is taking the complex and making it simple.”

Albert Einstein

Ahora tenemos una forma de crear un post directamente en la base de datos, con un simple clic y gracias a que tenemos una sesión de usuario abierta, también sabemos a quién asignarle el nuevo post. 👏🏼

Ahora pasemos a la ruta dinámica de la edición. 🔥

spaceman

¿List@ para ver todo el curso? Prepárate porque apenas estamos comenzando 🚀

¡Desbloquea el curso completo y conviértete en un PRO del desarrollo web! 🫶🏻 .