{"id":27985,"date":"2022-03-21T19:24:47","date_gmt":"2022-03-21T19:24:47","guid":{"rendered":"http:\/\/Building-a-User-Dashboard-with-Redwood"},"modified":"2022-03-21T19:24:47","modified_gmt":"2022-03-21T19:24:47","slug":"building-a-user-dashboard-with-redwood","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/","title":{"rendered":"Building a User Dashboard with Redwood"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>There\u2019s a dashboard for just about every application you log in to these days. Most of them are built with modern frameworks like React or Angular and they have some kind of back-end to support them. Users depend on these dashboards to check their account info, make updates to their businesses, and handle a number of other actions.<\/p>\n<p>In this tutorial, we\u2019ll be making a user dashboard for a management system with Redwood. It\u2019ll have a few actions that a user can take to add other users to the account with different roles. The dashboard will also let a user add new items to their inventory and the items will be attached to different locations.<\/p>\n<p>Let\u2019s kick it off with a little background on Redwood.<\/p>\n<h2>What is Redwood<\/h2>\n<p>Redwood is a full-stack framework built with Prisma, React, and GraphQL. It comes with a lot of features with a few commands that we\u2019ll be using to make this app quickly. If you\u2019re interested in learning more about Redwood, make sure to <a href=\"https:\/\/redwoodjs.com\/docs\/introduction\">check out their docs<\/a>.<\/p>\n<h2>Set up the project<\/h2>\n<p>Now let\u2019s jump into getting our dashboard set up. We\u2019ll bootstrap this app by running the following command. Just a heads up, it might take a few minutes for it to finish, but it\u2019ll be worth the wait.<\/p>\n<p><code>yarn create redwood-app .\/redwood-dashboard<\/code><\/p>\n<p>When the command has finished executing, you\u2019ll notice you have quite a few folders and files. The most important folders are the <code>api<\/code> directory and the <code>web<\/code> directory. The <code>api<\/code> directory holds all of the code for the back-end and database while the <code>web<\/code> directory holds everything for the front-end.<\/p>\n<p>Before we start working on the app, you should run it to see how it works first. Use the following command to start both the front-end and back-end.<\/p>\n<p><code>yarn rw dev<\/code><\/p>\n<p>Here\u2019s what you should see in your browser.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624049189\/e-603fc55d218a650069f5228b\/qeck1tbl8odgdkh3m1bc.png\" alt=\"base Redwood app\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1132\"\/><\/p>\n<h2>Defining the dashboard model<\/h2>\n<p>Since you\u2019ve seen the app in action, let\u2019s start taking advantage of some Redwood commands to work on the back-end. We\u2019ll start by making a Prisma model for the dashboard. This is how our app will connect to a Postgres database. Inside of the <code>api &gt; db<\/code>, open the <code>schema.prisma<\/code> file.<\/p>\n<p>This is where we\u2019ll make the schema for the tables we want in our database using a few different kinds of relations. You\u2019ll see that Redwood already has a few configs set and an example of a user model.<\/p>\n<p>We\u2019ll be changing the <code>datasource db provider<\/code> to <code>postgresql<\/code> which you can see in the code snippet below.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">datasource db {\n  provider = <span class=\"hljs-string\">\"postgresql\"<\/span>\n  url      = env(<span class=\"hljs-string\">\"DATABASE_URL\"<\/span>)\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Then we\u2019ll remove the <code>TODO<\/code> and update the example user model.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">model User {\n  id    Int    @id @<span class=\"hljs-keyword\">default<\/span>(autoincrement())\n  email <span class=\"hljs-built_in\">String<\/span> @unique\n  name  <span class=\"hljs-built_in\">String<\/span>\n  role  <span class=\"hljs-built_in\">String<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Our updated <code>User<\/code> model has a few columns for information we want to store about a user. The <code>email<\/code> field has a constraint that it always has to be a unique value. The same email address can\u2019t be in the database multiple times. Next, we\u2019ll add a new model for our <code>Item<\/code> and <code>Location<\/code> tables. These need to be created at the same time because they have a relationship with each other.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">model Item {\n  id         Int      @id @<span class=\"hljs-keyword\">default<\/span>(autoincrement())\n  sku        <span class=\"hljs-built_in\">String<\/span>   @unique\n  name       <span class=\"hljs-built_in\">String<\/span>\n  location   Location @relation(fields: &#91;locationId], <span class=\"hljs-attr\">references<\/span>: &#91;id])\n  locationId Int\n}\n\nmodel Location {\n  id       Int    @id @<span class=\"hljs-keyword\">default<\/span>(autoincrement())\n  name     <span class=\"hljs-built_in\">String<\/span>\n  district Int\n  Item     Item&#91;]\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Then we\u2019ll update the <code>seed.js<\/code> file so that there are a few values present before we start our app. This is common on product dashboards for populating dropdown options or initializing tags that users can add to different settings. We\u2019ll be adding a user, an item, and one location to seed our database. Just a heads up, I\u2019ve deleted a lot of comments from this file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/* eslint-disable no-console *\/<\/span>\n<span class=\"hljs-keyword\">const<\/span> { PrismaClient } = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'@prisma\/client'<\/span>)\n<span class=\"hljs-keyword\">const<\/span> dotenv = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'dotenv'<\/span>)\n\ndotenv.config()\n<span class=\"hljs-keyword\">const<\/span> db = <span class=\"hljs-keyword\">new<\/span> PrismaClient()\n\n<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">main<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-built_in\">console<\/span>.warn(<span class=\"hljs-string\">'Please define your seed data.'<\/span>)\n\n  <span class=\"hljs-keyword\">await<\/span> db.user.create({\n    <span class=\"hljs-attr\">data<\/span>: { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'Kaiya'<\/span>, <span class=\"hljs-attr\">email<\/span>: <span class=\"hljs-string\">'best@test.com'<\/span>, <span class=\"hljs-attr\">role<\/span>: <span class=\"hljs-string\">'inventory'<\/span> },\n  })\n\n  <span class=\"hljs-keyword\">await<\/span> db.location.create({\n    <span class=\"hljs-attr\">data<\/span>: { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'Compound North'<\/span>, <span class=\"hljs-attr\">district<\/span>: <span class=\"hljs-number\">1<\/span> },\n  })\n\n  <span class=\"hljs-keyword\">await<\/span> db.item.create({\n    <span class=\"hljs-attr\">data<\/span>: {\n      <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'Morning Glory'<\/span>,\n      <span class=\"hljs-attr\">sku<\/span>: <span class=\"hljs-string\">'hf8029ht8942ht8429pht8p942p'<\/span>,\n      <span class=\"hljs-attr\">locationId<\/span>: <span class=\"hljs-number\">1<\/span>,\n    },\n  })\n}\n\nmain()\n  .catch(<span class=\"hljs-function\">(<span class=\"hljs-params\">e<\/span>) =&gt;<\/span> <span class=\"hljs-built_in\">console<\/span>.error(e))\n  .finally(<span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    <span class=\"hljs-keyword\">await<\/span> db.$disconnect()\n  })\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>With the schema and seed data in place, we\u2019re almost ready to run our first migration. Before we do that, we need to be connected to the database. So in the <code>.env<\/code> file at the root of the project, update the <code>DATABASE_URL<\/code> to match your Postgres instance. It\u2019ll look similar to this.<\/p>\n<p><code>DATABASE_URL=postgres:\/\/postgres:admin@localhost:5432\/dashboard<\/code><\/p>\n<p>If you don\u2019t have a local Postgres instance to work with, <a href=\"https:\/\/www.postgresql.org\/download\/\">you can download it here<\/a> pretty quickly.<\/p>\n<p>Now we\u2019re going to run the migration with:<\/p>\n<p><code>yarn rw prisma migrate dev<\/code><\/p>\n<p>This will prompt you for a migration name, create the database and the tables, and add the seed data. If you look at your database through pgAdmin, you\u2019ll see something like this.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624049253\/e-603fc55d218a650069f5228b\/gjelsegxua1mgaiy3l5t.png\" alt=\"seeded database in pgAdmin\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1110\"\/><\/p>\n<p>Now that you have your database ready to store and send the values we need, let\u2019s move on to our back-end and front-end.<\/p>\n<h2>Adding the back-end and front-end<\/h2>\n<p>Redwood has one particular command that does a lot of work for us. It will create the entire CRUD for a table from the front-end components and routes to the back-end GraphQL queries, types, and mutations. We\u2019re going to take advantage of that to make most of our dashboard. Let\u2019s start with the following command.<\/p>\n<p><code>yarn rw g scaffold user<\/code><\/p>\n<p>This will generate several pages and components and GraphQL files to handle all of the CRUD actions for the user\u2019s portion of the dashboard. Take a look in <code>web &gt; pages<\/code>. You should see a new directory called <code>User<\/code>. This has all of the pages we need to handle everything about users.<\/p>\n<p>Now take a look in <code>web &gt; components<\/code>. There will be another <code>User<\/code> folder. This one contains the components we use to interact with the GraphQL server. Most of the data is fetched in these components and requests are sent from these components.<\/p>\n<p>The <code>web &gt; layouts<\/code> folder will also have a new directory containing a layout file for your <code>User<\/code> pages. This is how you can create styles for a specific set of pages.<\/p>\n<p>In the <code>Routes.js<\/code> file, you\u2019ll see there is a new set of routes for users wrapped in the <code>UserLayout<\/code>. All of the pages generate also have their routes automatically added to this file inside of their parent layout.<\/p>\n<p>There were also some new files generated in the <code>api<\/code> directory. If you look inside <code>api &gt; src &gt; graphql<\/code>, you\u2019ll find the GraphQL schema for all the CRUD operations you need and the types have been defined by the model in the <code>schema.prisma<\/code> file.<\/p>\n<p>Then inside <code>api &gt; src &gt; services<\/code>, you\u2019ll find all of the GraphQL resolvers for the queries and mutations defined in the schema.<\/p>\n<p>All of these pages, components, types, and resolvers were generated by that one Redwood command. Let\u2019s run the app with <code>yarn rw dev<\/code> so you can see all of this working. If you go to the <code>users<\/code> page in the browser, you should see something similar to this.<\/p>\n<p><strong>The home page will return a 404 right now because we haven\u2019t added a component for that route. We\u2019ll do that a bit later, but the <code>\/users<\/code> page will still work.<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624049294\/e-603fc55d218a650069f5228b\/z0ywmlzj1sywxdmw1vjf.png\" alt=\"users CRUD in browser\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1121\"\/><\/p>\n<p>You can add a new user, update the current user, or delete the current user with the buttons on the page.<\/p>\n<p>We\u2019re going to run that <code>scaffold<\/code> command two more times to generate the CRUD for the items and locations.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn rw g scaffold location\nyarn rw g scaffold item\n<\/code><\/span><\/pre>\n<p>Now we have all of the actions we need for our user dashboard. There are a couple of things we need to do to give this dashboard a more realistic feel. We\u2019ll add a home page and a layout to help us navigate between parts of the dashboard.<\/p>\n<h3>Making the home page<\/h3>\n<p>Let\u2019s start by adding the <code>styled-components<\/code> package because we\u2019re going to use it to style a few things. First, go to the <code>web<\/code> directory in your terminal. That\u2019s where this package will need to be installed.<\/p>\n<p><code>yarn add styled-components<\/code><\/p>\n<p>Now let\u2019s run one of those magic Redwood commands to generate the home page and its routing.<\/p>\n<p><code>yarn rw g page home \/<\/code><\/p>\n<p>This will create a new directory in <code>web &gt; src &gt; pages<\/code> for the <code>HomePage<\/code> component and it\u2019ll add a new route to <code>Routes.js<\/code>. You can re-run your app here to see the new home page. It\u2019ll look like this in the browser.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624049318\/e-603fc55d218a650069f5228b\/dcsgwketcrhpwiuddwq8.png\" alt=\"new home page\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1130\"\/><\/p>\n<p>Now that we have a home page in place, let\u2019s make a layout that will apply to this and all the other pages we have so far. Of course, there\u2019s a Redwood command to handle that.<\/p>\n<p><code>yarn rw g layout home<\/code><\/p>\n<p>This will create a new folder in <code>web &gt; src &gt; layouts<\/code> for our home page. We\u2019re going to use a few styled components in the <code>HomeLayout<\/code> component to create a side navigation menu and give the dashboard a little definition. We\u2019ll also be using Redwood routing to add links to the other pages in the side navigation.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { Link, routes } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@redwoodjs\/router'<\/span>\n<span class=\"hljs-keyword\">import<\/span> styled <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'styled-components'<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> HomeLayout = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ children }<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">FlexBox<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SideNav<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">LinkContainer<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span> <span class=\"hljs-attr\">to<\/span>=<span class=\"hljs-string\">{routes.users()}<\/span>&gt;<\/span>Users<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">LinkContainer<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">LinkContainer<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span> <span class=\"hljs-attr\">to<\/span>=<span class=\"hljs-string\">{routes.locations()}<\/span>&gt;<\/span>Locations<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">LinkContainer<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">LinkContainer<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span> <span class=\"hljs-attr\">to<\/span>=<span class=\"hljs-string\">{routes.items()}<\/span>&gt;<\/span>Items<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">LinkContainer<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">SideNav<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">FullPage<\/span>&gt;<\/span>{children}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">FullPage<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">FlexBox<\/span>&gt;<\/span><\/span>\n  )\n}\n\n<span class=\"hljs-keyword\">const<\/span> FlexBox = styled.div<span class=\"hljs-string\">`\n  display: flex;\n`<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> FullPage = styled.div<span class=\"hljs-string\">`\n  height: 100vh;\n  width: 100%;\n`<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> LinkContainer = styled.div<span class=\"hljs-string\">`\n  padding: 12px;\n\n  &gt; * {\n    color: #000;\n    font-family: sans-serif;\n    font-size: 18px;\n    text-decoration: none;\n  }\n\n  &gt; *:hover {\n    color: #5b5b5b;\n  }\n`<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> SideNav = styled.nav<span class=\"hljs-string\">`\n  border-right: 1px solid;\n  width: 250px;\n`<\/span>\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> HomeLayout\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, we need to apply this layout to all of the pages in our app. We\u2019ll do that in the <code>Routes.js<\/code> file. This means adding a <code>&lt;Set&gt;<\/code> component around all of the existing routes like below.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">...\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Router<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Set<\/span> <span class=\"hljs-attr\">wrap<\/span>=<span class=\"hljs-string\">{HomeLayout}<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{HomePage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"home\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Set<\/span> <span class=\"hljs-attr\">wrap<\/span>=<span class=\"hljs-string\">{ItemsLayout}<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/items\/new\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{ItemNewItemPage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"newItem\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/items\/{id:Int}\/edit\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{ItemEditItemPage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"editItem\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/items\/{id:Int}\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{ItemItemPage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"item\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/items\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{ItemItemsPage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"items\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Set<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Set<\/span> <span class=\"hljs-attr\">wrap<\/span>=<span class=\"hljs-string\">{LocationsLayout}<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/locations\/new\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{LocationNewLocationPage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"newLocation\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/locations\/{id:Int}\/edit\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{LocationEditLocationPage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"editLocation\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/locations\/{id:Int}\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{LocationLocationPage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"location\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/locations\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{LocationLocationsPage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"locations\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Set<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Set<\/span> <span class=\"hljs-attr\">wrap<\/span>=<span class=\"hljs-string\">{UsersLayout}<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/users\/new\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{UserNewUserPage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"newUser\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/users\/{id:Int}\/edit\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{UserEditUserPage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"editUser\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/users\/{id:Int}\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{UserUserPage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"user\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/users\"<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{UserUsersPage}<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"users\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Set<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">notfound<\/span> <span class=\"hljs-attr\">page<\/span>=<span class=\"hljs-string\">{NotFoundPage}<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Set<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Router<\/span>&gt;<\/span>\n...\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Now if you run <code>yarn rw dev<\/code>, you\u2019ll see something like this.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624049368\/e-603fc55d218a650069f5228b\/cmymcv9omp6le8jud6oc.png\" alt=\"dashboard with global layout applied\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1143\"\/><\/p>\n<p>If you go any of the links in the side navigation, you\u2019ll see something like this.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624049383\/e-603fc55d218a650069f5228b\/dqgaomfednzrvetjgk0l.png\" alt=\"users in the dashboard with layout\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1143\"\/><\/p>\n<p>I\u2019ll leave the extra styling to you. Styling this could be a completely separate tutorial!<\/p>\n<p>This might feel like a cliffhanger since we didn\u2019t actually write much code, but that\u2019s what I like about Redwood. You can get big apps up and running quickly and things just work.<\/p>\n<h2>Finished code<\/h2>\n<p>You can check out the front-end without the connection to the back-end here on this <a href=\"https:\/\/codesandbox.io\/s\/runtime-water-1fvey?file=\/src\/App.js\">Code Sandbox<\/a>.<\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/runtime-water-1fvey?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"runtime-water-1fvey\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><p>If you want all of the code for the front-end and back-end, check out the <a href=\"https:\/\/github.com\/flippedcoder\/blog-examples\/tree\/main\/redwood-user-dashboard\"><code>redwood-user-dashboard<\/code> in this Git repo<\/a>!<\/p>\n<h2>Conclusion<\/h2>\n<p>Dashboards are a major part of many apps so it\u2019s helpful to know how to create one quickly. Redwood is a framework that will help you get started with advanced projects like these and it makes it fast to generate complex structures.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":27986,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[379,134,370,177,246,371],"class_list":["post-27985","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-graphql","tag-guest-post","tag-image","tag-javascript","tag-react","tag-under-review"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Building a User Dashboard with Redwood<\/title>\n<meta name=\"description\" content=\"Dashboards are a common part of many apps, but they are so complex with the amount of data they handle. We&#039;re going to use Redwood to make a user dashboard with a database, back-end, and front-end all connected.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building a User Dashboard with Redwood\" \/>\n<meta property=\"og:description\" content=\"Dashboards are a common part of many apps, but they are so complex with the amount of data they handle. We&#039;re going to use Redwood to make a user dashboard with a database, back-end, and front-end all connected.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-03-21T19:24:47+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925761\/Web_Assets\/blog\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"3048\" \/>\n\t<meta property=\"og:image:height\" content=\"2024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Building a User Dashboard with Redwood\",\"datePublished\":\"2022-03-21T19:24:47+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/\"},\"wordCount\":6,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925761\/Web_Assets\/blog\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a.jpg?_i=AA\",\"keywords\":[\"GraphQL\",\"Guest Post\",\"Image\",\"Javascript\",\"React\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/\",\"name\":\"Building a User Dashboard with Redwood\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925761\/Web_Assets\/blog\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a.jpg?_i=AA\",\"datePublished\":\"2022-03-21T19:24:47+00:00\",\"description\":\"Dashboards are a common part of many apps, but they are so complex with the amount of data they handle. We're going to use Redwood to make a user dashboard with a database, back-end, and front-end all connected.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925761\/Web_Assets\/blog\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925761\/Web_Assets\/blog\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a.jpg?_i=AA\",\"width\":3048,\"height\":2024},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building a User Dashboard with Redwood\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Building a User Dashboard with Redwood","description":"Dashboards are a common part of many apps, but they are so complex with the amount of data they handle. We're going to use Redwood to make a user dashboard with a database, back-end, and front-end all connected.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/","og_locale":"en_US","og_type":"article","og_title":"Building a User Dashboard with Redwood","og_description":"Dashboards are a common part of many apps, but they are so complex with the amount of data they handle. We're going to use Redwood to make a user dashboard with a database, back-end, and front-end all connected.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-03-21T19:24:47+00:00","og_image":[{"width":3048,"height":2024,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925761\/Web_Assets\/blog\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a.jpg?_i=AA","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/"},"author":{"name":"","@id":""},"headline":"Building a User Dashboard with Redwood","datePublished":"2022-03-21T19:24:47+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/"},"wordCount":6,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925761\/Web_Assets\/blog\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a.jpg?_i=AA","keywords":["GraphQL","Guest Post","Image","Javascript","React","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/","name":"Building a User Dashboard with Redwood","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925761\/Web_Assets\/blog\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a.jpg?_i=AA","datePublished":"2022-03-21T19:24:47+00:00","description":"Dashboards are a common part of many apps, but they are so complex with the amount of data they handle. We're going to use Redwood to make a user dashboard with a database, back-end, and front-end all connected.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925761\/Web_Assets\/blog\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925761\/Web_Assets\/blog\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a.jpg?_i=AA","width":3048,"height":2024},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-user-dashboard-with-redwood\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Building a User Dashboard with Redwood"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925761\/Web_Assets\/blog\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a\/49a52956b72264aff565db19c3f364eeee90e0a9-3048x2024-1_279867a09a.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27985","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=27985"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27985\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/27986"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=27985"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=27985"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=27985"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}