{"id":28153,"date":"2022-04-19T17:10:26","date_gmt":"2022-04-19T17:10:26","guid":{"rendered":"http:\/\/build-an-inventory-tracker"},"modified":"2022-04-19T17:10:26","modified_gmt":"2022-04-19T17:10:26","slug":"build-an-inventory-tracker","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/","title":{"rendered":"Build an Inventory Tracker"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>This will use Next.js to let users upload images of their items and do immediate updates as an admin.<\/p>\n<h2>Initial setup<\/h2>\n<p>There are a couple of things you need to have in place before we start working on the Next app. First, we\u2019ll be using Cloudinary to host the product images. So if you don\u2019t have a free account, you can go make one <a href=\"https:\/\/cloudinary.com\/users\/register\/free\">here<\/a>. We\u2019ll also be using a PostgreSQL database to hold all of the product data, so if you don\u2019t have a local instance, you can <a href=\"https:\/\/www.postgresql.org\/download\/\">download it for free here<\/a>.<\/p>\n<h2>Create a new Next app<\/h2>\n<p>Now we can dive straight into the app and start by generating a new Next project. Run the following command in your terminal:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn create next-app --typescript\n<\/code><\/span><\/pre>\n<p>This will create a new Next project and it will prompt you for a name. I\u2019ve called this project <code>inventory-tracker<\/code>, but feel free to call it anything you like. We\u2019re going to use Next\u2019s built-in <a href=\"https:\/\/nextjs.org\/docs\/api-routes\/introduction\">API routes<\/a> to handle our database operations since it\u2019s basic CRUD operations. Since we\u2019re talking about the database, let\u2019s go ahead and set up <a href=\"https:\/\/www.prisma.io\/docs\/\">Prisma<\/a> to handle those operations with our local Postgres instance.<\/p>\n<h3>Prisma set up<\/h3>\n<p>Let\u2019s start by adding the <code>prisma<\/code> package to the project with the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn add prisma @prisma\/client\n<\/code><\/span><\/pre>\n<p>Now we can use the Prisma CLI to make the config files we need to connect our project to Postgres. Run the following command to set up Prisma:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ npx prisma init\n<\/code><\/span><\/pre>\n<p>This generates a <code>.env<\/code> file at the root of your project and a new <code>prisma<\/code> directory that has the <code>schema.prisma<\/code> file that connects the whole app to Postgres. This is also where we will define the database schema. But first, open the <code>.env<\/code> file and update the connection string with your local Postgres username, password, and database name.<\/p>\n<h3>Defining the database schema<\/h3>\n<p>Now open the <code>schema.prisma<\/code> file because we can add the models for the table we\u2019ll use here. Below the <code>datasource<\/code> where we define the connection to the database, add the following code:<\/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\"><span class=\"hljs-comment\">\/\/ schema.prisma<\/span>\n...\nmodel Product {\n  id       <span class=\"hljs-built_in\">String<\/span> @id @<span class=\"hljs-keyword\">default<\/span>(uuid())\n  name     <span class=\"hljs-built_in\">String<\/span>\n  sku      <span class=\"hljs-built_in\">String<\/span> @<span class=\"hljs-keyword\">default<\/span>(uuid())\n  image    <span class=\"hljs-built_in\">String<\/span>\n  quantity Int\n  storeId  <span class=\"hljs-built_in\">String<\/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>This defines the columns of the <code>Product<\/code> table that will help us keep all the items in multiple stores available. Now that we have the database defined, we can run a migration to make these changes in the database.<\/p>\n<h3>Migrating changes to the database<\/h3>\n<p>We\u2019ll run another command to handle the migration using Prisma. In your terminal, run this:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ npx prisma migrate dev --name init\n<\/code><\/span><\/pre>\n<p>This will create the <code>Product<\/code> table in your database with all the fields we have defined. Now we can move on to the API route for this app. We\u2019ll write all of the CRUD logic for it in a new file.<\/p>\n<h2>Adding a Next API route<\/h2>\n<p>Go to the <code>pages &gt; api<\/code> directory and add a new file called <code>inventory.ts<\/code>. This is where we\u2019ll make the calls to our database using Prisma. Open this file and add the follow code:<\/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\"><span class=\"hljs-comment\">\/\/ inventory.ts<\/span>\n<span class=\"hljs-keyword\">import<\/span> type { NextApiRequest, NextApiResponse } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { PrismaClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@prisma\/client\"<\/span>;\n\ninterface Product {\n  <span class=\"hljs-attr\">id<\/span>: string;\n  name: string;\n  sku: string;\n  image: string;\n  quantity: number;\n  storeId: string;\n}\n\n<span class=\"hljs-keyword\">const<\/span> prisma = <span class=\"hljs-keyword\">new<\/span> PrismaClient();\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handler<\/span>(<span class=\"hljs-params\">\n  req: NextApiRequest,\n  res: NextApiResponse&lt;Product&#91;] | Product | null&gt;\n<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">switch<\/span> (req.query.type) {\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"products\"<\/span>:\n      getAllProducts(req, res);\n      <span class=\"hljs-keyword\">break<\/span>;\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"product\"<\/span>:\n      getProduct(req, res);\n      <span class=\"hljs-keyword\">break<\/span>;\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"create\"<\/span>:\n      createProduct(req, res);\n      <span class=\"hljs-keyword\">break<\/span>;\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"update\"<\/span>:\n      updateProduct(req, res);\n      <span class=\"hljs-keyword\">break<\/span>;\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"delete\"<\/span>:\n      deleteProduct(req, res);\n      <span class=\"hljs-keyword\">break<\/span>;\n    <span class=\"hljs-keyword\">default<\/span>:\n      res.status(<span class=\"hljs-number\">200<\/span>).json(&#91;]);\n  }\n}\n\n<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getAllProducts<\/span>(<span class=\"hljs-params\">\n  req: NextApiRequest,\n  res: NextApiResponse&lt;Product&#91;]&gt;\n<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> allProducts = <span class=\"hljs-keyword\">await<\/span> prisma.product.findMany();\n\n  res.status(<span class=\"hljs-number\">200<\/span>).json(allProducts || &#91;]);\n}\n\n<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getProduct<\/span>(<span class=\"hljs-params\">\n  req: NextApiRequest,\n  res: NextApiResponse&lt;Product | null&gt;\n<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> product = <span class=\"hljs-keyword\">await<\/span> prisma.product.findUnique({\n    <span class=\"hljs-attr\">where<\/span>: {\n      <span class=\"hljs-attr\">id<\/span>: req.body.id,\n    },\n  });\n\n  res.status(<span class=\"hljs-number\">200<\/span>).json(product);\n}\n\n<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">createProduct<\/span>(<span class=\"hljs-params\">\n  req: NextApiRequest,\n  res: NextApiResponse&lt;Product&gt;\n<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> newProduct = <span class=\"hljs-keyword\">await<\/span> prisma.product.create({\n    <span class=\"hljs-attr\">data<\/span>: {\n      <span class=\"hljs-attr\">name<\/span>: req.body.product.name,\n      <span class=\"hljs-attr\">sku<\/span>: req.body.product.sku,\n      <span class=\"hljs-attr\">image<\/span>: req.body.product.image,\n      <span class=\"hljs-attr\">quantity<\/span>: req.body.product.quantity,\n      <span class=\"hljs-attr\">storeId<\/span>: req.body.product.storeId,\n    },\n  });\n\n  res.status(<span class=\"hljs-number\">200<\/span>).json(newProduct);\n}\n\n<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">updateProduct<\/span>(<span class=\"hljs-params\">\n  req: NextApiRequest,\n  res: NextApiResponse&lt;Product&gt;\n<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> updatedProduct = <span class=\"hljs-keyword\">await<\/span> prisma.product.update({\n    <span class=\"hljs-attr\">where<\/span>: { <span class=\"hljs-attr\">id<\/span>: req.body.modifiedProduct.id },\n    <span class=\"hljs-attr\">data<\/span>: {\n      <span class=\"hljs-attr\">name<\/span>: req.body.modifiedProduct.name,\n      <span class=\"hljs-attr\">sku<\/span>: req.body.modifiedProduct.sku,\n      <span class=\"hljs-attr\">image<\/span>: req.body.modifiedProduct.image,\n      <span class=\"hljs-attr\">quantity<\/span>: req.body.modifiedProduct.quantity,\n      <span class=\"hljs-attr\">storeId<\/span>: req.body.modifiedProduct.storeId,\n    },\n  });\n\n  res.status(<span class=\"hljs-number\">200<\/span>).json(updatedProduct);\n}\n\n<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">deleteProduct<\/span>(<span class=\"hljs-params\">\n  req: NextApiRequest,\n  res: NextApiResponse&lt;Product&gt;\n<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> deleteProduct = <span class=\"hljs-keyword\">await<\/span> prisma.product.delete({\n    <span class=\"hljs-attr\">where<\/span>: { <span class=\"hljs-attr\">id<\/span>: req.body.productId },\n  });\n\n  res.status(<span class=\"hljs-number\">200<\/span>).json(deleteProduct);\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>There\u2019s quite a bit going on here so we\u2019ll walk through it. We import some package and then define the <code>Product<\/code> type to appease TypeScript requirements. Then we instantiate a new Prisma client to connect to our database. After that is the <code>handler<\/code> function. This will take the request and call a different function based on the referer value. Finally, we have the <code>getProducts<\/code>, <code>getProduct<\/code>, <code>createProduct<\/code>, <code>updateProduct<\/code>, and <code>deleteProduct<\/code> methods.<\/p>\n<p>These make all of the database queries that get sent to our Postgres instance. Each of these methods returns a product-typed response to the requester. So if you want to do some testing in Postman before you work with the front-end. Once you feel like your endpoints are good to go, we can switch over to the front-end.<\/p>\n<h2>Setting up <a href=\"https:\/\/tailwindcss.com\/\">Tailwind CSS<\/a><\/h2>\n<p>We\u2019re going to use Tailwind CSS to handle our styles so let\u2019s install that package with the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn add tailwindcss postcss autoprefixer @heroicons\/react axios\n<\/code><\/span><\/pre>\n<p>Then run the following command to initialize Tailwind in the project:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ npx tailwindcss init -p\n<\/code><\/span><\/pre>\n<p>This will add a new file to the root of your directory called <code>tailwind.config.js<\/code> and it handles all of the settings you choose for Tailwind. Open this file and update the <code>content<\/code> line to match this:<\/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\"><span class=\"hljs-comment\">\/\/ tailwind.config.js<\/span>\n...\ncontent: &#91;\n    <span class=\"hljs-string\">\".\/pages\/**\/*.{js,ts,jsx,tsx}\"<\/span>,\n    <span class=\"hljs-string\">\".\/components\/**\/*.{js,ts,jsx,tsx}\"<\/span>,\n  ],\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>This makes it so Tailwind knows which files to style. Now go to <code>styles &gt; globals.css<\/code> and delete all of the styles. We\u2019re going to add these Tailwind directives to this stylesheet so we can use the classes throughout the front-end:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-keyword\">@tailwind<\/span> base;\n<span class=\"hljs-keyword\">@tailwind<\/span> components;\n<span class=\"hljs-keyword\">@tailwind<\/span> utilities;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Let\u2019s update one more config file so that we\u2019re able to get our images from Cloudinary. This will let Next access the source for any images. Open the <code>next.config.ts<\/code> file at the root of the project and make the following update:<\/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-comment\">\/\/ next.config.ts<\/span>\n<span class=\"hljs-keyword\">const<\/span> nextConfig = {\n  <span class=\"hljs-attr\">reactStrictMode<\/span>: <span class=\"hljs-literal\">true<\/span>,\n  <span class=\"hljs-attr\">images<\/span>: {\n    <span class=\"hljs-attr\">domains<\/span>: &#91;<span class=\"hljs-string\">'res.cloudinary.com'<\/span>]\n  },\n...\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>Now that Tailwind is ready to go, let\u2019s create the main view for the products.<\/p>\n<h2>Displaying, editing, adding, and deleting products<\/h2>\n<p>In the <code>pages<\/code> directory, open the <code>index.tsx<\/code> file and delete all of the existing code. This page will be the product table that lists everything in the inventory and there will be buttons that allow us to create new products or interact with existing ones. Let\u2019s start by adding a few imports and a type dedinition at the top of the file:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ index.tsx<\/span>\n<span class=\"hljs-keyword\">import<\/span> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> axios <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"axios\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> Image <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\/image\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> {\n  PlusCircleIcon,\n  PencilAltIcon,\n  TrashIcon,\n} <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@heroicons\/react\/solid\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> Modal <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/components\/Modal\"<\/span>;\n\ninterface Product {\n  <span class=\"hljs-attr\">id<\/span>: string;\n  name: string;\n  sku: string;\n  image: string;\n  quantity: number;\n  storeId: string;\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\">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>We\u2019ll make the <code>Modal<\/code> component a little later, so for now we\u2019ll add the request to get the product information from the back-end using our API route. We\u2019ll use the <code>getServerSideProps<\/code> method because we want this page to update every time a user visits it so they can get the most recent information. Add the following code to the bottom of the file:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ index.tsx<\/span>\n...\nexport <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getServerSideProps<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> productsRes = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">'http:\/\/localhost:3000\/api\/inventory?type=products'<\/span>)\n\n  <span class=\"hljs-keyword\">const<\/span> products = <span class=\"hljs-keyword\">await<\/span> productsRes.json()\n\n  <span class=\"hljs-keyword\">return<\/span> {\n    <span class=\"hljs-attr\">props<\/span>: {\n      products\n    },\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><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>Now we can focus on what gets rendered on the page. In between the <code>Product<\/code> type definition and the server-side request for all the products, add the following code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ index.tsx<\/span>\n...\nexport <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Products<\/span>(<span class=\"hljs-params\">{ products }<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#91;newModal, setNewModal] = useState&lt;boolean&gt;(<span class=\"hljs-literal\">false<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;editModal, setEditModal] = useState&lt;boolean&gt;(<span class=\"hljs-literal\">false<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;index, setIndex] = useState&lt;number&gt;(<span class=\"hljs-number\">0<\/span>);\n\n  <span class=\"hljs-keyword\">const<\/span> deleteProduct = <span class=\"hljs-keyword\">async<\/span> (productId: string) =&gt; {\n    <span class=\"hljs-keyword\">await<\/span> axios.delete(<span class=\"hljs-string\">\"\/api\/inventory?type=delete\"<\/span>, { <span class=\"hljs-attr\">data<\/span>: { productId } });\n  };\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex gap-2\"<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> setNewModal(true)}&gt;\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex gap-2 bg-gray-700 hover:bg-gray-300 text-white font-bold py-2 px-4 rounded-full m-6\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PlusCircleIcon<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"h-6 w-6 text-green-500\"<\/span> \/&gt;<\/span>\n          Add a product\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex flex-col gap-2\"<\/span>&gt;<\/span>\n        {products.length &gt; 0 ? (\n          products.map((product: Product, index: number) =&gt; (\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{product.id}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex gap-6 border-b-2 w-full\"<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Image<\/span>\n                <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{product.image}<\/span>\n                <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">{product.name}<\/span>\n                <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"100\"<\/span>\n                <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">\"100\"<\/span>\n              \/&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>{product.name}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>{product.quantity}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>{product.storeId}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PencilAltIcon<\/span>\n                <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"h-6 w-6 text-indigo-500\"<\/span>\n                <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> {\n                  setIndex(index);\n                  setEditModal(true);\n                }}\n              \/&gt;\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TrashIcon<\/span>\n                <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"h-6 w-6 text-red-400\"<\/span>\n                <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> deleteProduct(product.id)}\n              \/&gt;\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          ))\n        ) : (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>Add some new products<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        )}\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      {newModal &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Modal<\/span> <span class=\"hljs-attr\">product<\/span>=<span class=\"hljs-string\">{{}}<\/span> <span class=\"hljs-attr\">onCancel<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> setNewModal(false)} \/&gt;}\n      {editModal &amp;&amp; (\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Modal<\/span> <span class=\"hljs-attr\">product<\/span>=<span class=\"hljs-string\">{products&#91;index]}<\/span> <span class=\"hljs-attr\">onCancel<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> setEditModal(false)} \/&gt;\n      )}\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}\n...\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><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>There\u2019s a lot happening in this component. First, we define a few states we\u2019ll need to toggle whether a modal needs to be displayed or not and the index of the product that will get sent to the modal if necessary.<\/p>\n<p>Then we have the function that will delete a product record if we need to. It makes a request to the back-end and sends the product id so the correct record is removed.<\/p>\n<p>Finally, we\u2019re rendering a button to add new products and then displaying the default message or the product data as rows on the page and each row has product information and a couple of buttons that either display an edit modal or trigger a delete action for that product.<\/p>\n<p>If you run the app with <code>yarn dev<\/code> now, you should see something like this.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1649723192\/e-603fc55d218a650069f5228b\/siag4rgz2bglmzvip77m.png\" alt=\"page without any product data\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1730\" height=\"872\"\/><\/p>\n<p>We have all of the CRUD functionality in place so all that\u2019s left is adding that <code>Modal<\/code> component we referenced earlier.<\/p>\n<h2>Product modal component<\/h2>\n<p>Now we\u2019ll need to add a new folder to the root of the project called <code>components<\/code> and then add a new file called <code>Modal.tsx<\/code>. This component will have a lot of Tailwind styling on it, a few props passed from the <code>index.tsx<\/code> file and a couple of functions. Add the following code to this file and we can go over what\u2019s happening.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ Modal.tsx<\/span>\n<span class=\"hljs-keyword\">import<\/span> axios <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"axios\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Modal<\/span>(<span class=\"hljs-params\">{ product, onCancel }<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> addProduct = <span class=\"hljs-keyword\">async<\/span> (e) =&gt; {\n    e.preventDefault();\n\n    <span class=\"hljs-keyword\">const<\/span> product = {\n      <span class=\"hljs-attr\">name<\/span>: e.target.name.value,\n      <span class=\"hljs-attr\">sku<\/span>: e.target.sku.value,\n      <span class=\"hljs-attr\">image<\/span>: e.target.image.value,\n      <span class=\"hljs-attr\">quantity<\/span>: <span class=\"hljs-built_in\">Number<\/span>(e.target.quantity.value),\n      <span class=\"hljs-attr\">storeId<\/span>: e.target.storeId.value,\n    };\n\n    <span class=\"hljs-keyword\">await<\/span> axios.post(<span class=\"hljs-string\">\"\/api\/inventory?type=create\"<\/span>, { product });\n\n    onCancel();\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> updateProduct = <span class=\"hljs-keyword\">async<\/span> (e) =&gt; {\n    e.preventDefault();\n\n    <span class=\"hljs-keyword\">const<\/span> modifiedProduct = {\n      <span class=\"hljs-attr\">id<\/span>: product.id,\n      <span class=\"hljs-attr\">name<\/span>: e.target.name.value,\n      <span class=\"hljs-attr\">sku<\/span>: e.target.sku.value,\n      <span class=\"hljs-attr\">image<\/span>: e.target.image.value,\n      <span class=\"hljs-attr\">quantity<\/span>: <span class=\"hljs-built_in\">Number<\/span>(e.target.quantity.value),\n      <span class=\"hljs-attr\">storeId<\/span>: e.target.storeId.value,\n    };\n\n    <span class=\"hljs-keyword\">await<\/span> axios.patch(<span class=\"hljs-string\">\"\/api\/inventory?type=update\"<\/span>, { modifiedProduct });\n\n    onCancel();\n  };\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>\n      <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"fixed z-10 inset-0 overflow-y-auto\"<\/span>\n      <span class=\"hljs-attr\">aria-labelledby<\/span>=<span class=\"hljs-string\">\"modal-title\"<\/span>\n      <span class=\"hljs-attr\">role<\/span>=<span class=\"hljs-string\">\"dialog\"<\/span>\n      <span class=\"hljs-attr\">aria-modal<\/span>=<span class=\"hljs-string\">\"true\"<\/span>\n    &gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>\n          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity\"<\/span>\n          <span class=\"hljs-attr\">aria-hidden<\/span>=<span class=\"hljs-string\">\"true\"<\/span>\n        &gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>\n          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"hidden sm:inline-block sm:align-middle sm:h-screen\"<\/span>\n          <span class=\"hljs-attr\">aria-hidden<\/span>=<span class=\"hljs-string\">\"true\"<\/span>\n        &gt;<\/span>\n          <span class=\"hljs-symbol\">&amp;#8203;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"relative inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"sm:flex sm:items-start\"<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left\"<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span>\n                  <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-lg leading-6 font-medium text-gray-900\"<\/span>\n                  <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"modal-title\"<\/span>\n                &gt;<\/span>\n                  Add a new product\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"mt-2\"<\/span>&gt;<\/span>\n                  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span>\n                    <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full max-w-sm\"<\/span>\n                    <span class=\"hljs-attr\">onSubmit<\/span>=<span class=\"hljs-string\">{product<\/span> ? <span class=\"hljs-attr\">updateProduct<\/span> <span class=\"hljs-attr\">:<\/span> <span class=\"hljs-attr\">addProduct<\/span>}\n                  &gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:flex md:items-center mb-6\"<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-1\/3\"<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span>\n                          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4\"<\/span>\n                          <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"name\"<\/span>\n                        &gt;<\/span>\n                          Product Name\n                        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-2\/3\"<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n                          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500\"<\/span>\n                          <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"product-name\"<\/span>\n                          <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"name\"<\/span>\n                          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span>\n                          <span class=\"hljs-attr\">defaultValue<\/span>=<span class=\"hljs-string\">{product<\/span> ? <span class=\"hljs-attr\">product.name<\/span> <span class=\"hljs-attr\">:<\/span> \"\"}\n                        \/&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:flex md:items-center mb-6\"<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-1\/3\"<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span>\n                          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4\"<\/span>\n                          <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"sku\"<\/span>\n                        &gt;<\/span>\n                          SKU\n                        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-2\/3\"<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n                          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500\"<\/span>\n                          <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"sku\"<\/span>\n                          <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"sku\"<\/span>\n                          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span>\n                          <span class=\"hljs-attr\">defaultValue<\/span>=<span class=\"hljs-string\">{product<\/span> ? <span class=\"hljs-attr\">product.sku<\/span> <span class=\"hljs-attr\">:<\/span> \"\"}\n                        \/&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:flex md:items-center mb-6\"<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-1\/3\"<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span>\n                          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4\"<\/span>\n                          <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"quantity\"<\/span>\n                        &gt;<\/span>\n                          Quantity\n                        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-2\/3\"<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n                          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500\"<\/span>\n                          <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"quantity\"<\/span>\n                          <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"quantity\"<\/span>\n                          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"number\"<\/span>\n                          <span class=\"hljs-attr\">defaultValue<\/span>=<span class=\"hljs-string\">{product<\/span> ? <span class=\"hljs-attr\">product.quantity<\/span> <span class=\"hljs-attr\">:<\/span> <span class=\"hljs-attr\">0<\/span>}\n                        \/&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:flex md:items-center mb-6\"<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-1\/3\"<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span>\n                          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4\"<\/span>\n                          <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"image\"<\/span>\n                        &gt;<\/span>\n                          Image\n                        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-2\/3\"<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n                          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500\"<\/span>\n                          <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"image\"<\/span>\n                          <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"image\"<\/span>\n                          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span>\n                          <span class=\"hljs-attr\">defaultValue<\/span>=<span class=\"hljs-string\">{product<\/span> ? <span class=\"hljs-attr\">product.image<\/span> <span class=\"hljs-attr\">:<\/span> \"\"}\n                        \/&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:flex md:items-center mb-6\"<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-1\/3\"<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span>\n                          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4\"<\/span>\n                          <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"storeId\"<\/span>\n                        &gt;<\/span>\n                          Store Id\n                        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-2\/3\"<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n                          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500\"<\/span>\n                          <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"storeId\"<\/span>\n                          <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"storeId\"<\/span>\n                          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span>\n                          <span class=\"hljs-attr\">defaultValue<\/span>=<span class=\"hljs-string\">{product<\/span> ? <span class=\"hljs-attr\">product.storeId<\/span> <span class=\"hljs-attr\">:<\/span> \"\"}\n                        \/&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:flex md:items-center\"<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-1\/3\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-1\/3\"<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span>\n                          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"shadow bg-purple-500 hover:bg-purple-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded\"<\/span>\n                          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"button\"<\/span>\n                          <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{onCancel}<\/span>\n                        &gt;<\/span>\n                          Cancel\n                        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"md:w-2\/3\"<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span>\n                          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"shadow bg-purple-500 hover:bg-purple-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded\"<\/span>\n                          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span>\n                        &gt;<\/span>\n                          Save Product\n                        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n                      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n                  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><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>We have just one import in this component so that we can use the <code>axios<\/code> package. Then the <code>Modal<\/code> component takes in an optional <code>product<\/code> object and a required <code>onCancel<\/code> method. After this, we define the calls to the back-end to create or edit a product. In the rendered elements, we do a quick check to see if there has been a product passed to the modal.<\/p>\n<p>If there is, we create our rows of products and if there is a product passed, we show the default message as we saw earlier. Either way, we render a form with the product fields we can set values for. If the product info is available, it will be set as the default value for the fields. The submit function also updates based on whether we are editing existing information or not.<\/p>\n<p>Now if you run the app and click the add product button, your page should look like this.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1649723907\/e-603fc55d218a650069f5228b\/kipgqxdocjllwrkqp220.png\" alt=\"new product modal\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1101\"\/><\/p>\n<h2>Add a new product<\/h2>\n<p>All of the functionality is connected now, so all we have to do is start adding new products to the inventory. With your modal open, go ahead and add some info for a product and save it.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1649726434\/e-603fc55d218a650069f5228b\/wmbnlyakjwwsenlzaoox.png\" alt=\"new product info\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1111\"\/><\/p>\n<p>When you refresh the page, you\u2019ll see something similar to this.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1649726434\/e-603fc55d218a650069f5228b\/wmbnlyakjwwsenlzaoox.png\" alt=\"product row\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1111\"\/><\/p>\n<p>That\u2019s everything! Now you have a fully functional inventory app.<\/p>\n<h2>Finished code<\/h2>\n<p>You can check out all of the code in the <code>inventory-tracker<\/code> folder of <a href=\"https:\/\/github.com\/flippedcoder\/media-projects\/tree\/main\/inventory-tracker\">this repo<\/a>. You can also check out the app in <a href=\"https:\/\/codesandbox.io\/s\/using-tailwind-with-next-js-forked-jp1riy\">this Code Sandbox<\/a>.<\/p>\n<p>&lt;CodeSandBox\ntitle=\u201cusing-tailwind-with-next-js-forked-jp1riy\u201d\nid=\u201cusing-tailwind-with-next-js-forked-jp1riy\u201d\n\/&gt;<\/p>\n<h2>Conclusion<\/h2>\n<p>Once you have the CRUD functionality set up for an app, you can expand it in a number of directions. You could make more advanced data displays so that users see the important statuses earlier. Or you can take the front-end and make it more user-friendly.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28154,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,212,246,371],"class_list":["post-28153","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-next-js","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>Build an Inventory Tracker<\/title>\n<meta name=\"description\" content=\"Sometimes you need to take a quick look at what you have available, whether it&#039;s at a store level or a home level. We&#039;re going to build a quick inventory app to handle this for us.\" \/>\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\/build-an-inventory-tracker\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build an Inventory Tracker\" \/>\n<meta property=\"og:description\" content=\"Sometimes you need to take a quick look at what you have available, whether it&#039;s at a store level or a home level. We&#039;re going to build a quick inventory app to handle this for us.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-04-19T17:10:26+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925282\/Web_Assets\/blog\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"3120\" \/>\n\t<meta property=\"og:image:height\" content=\"2080\" \/>\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\/build-an-inventory-tracker\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Build an Inventory Tracker\",\"datePublished\":\"2022-04-19T17:10:26+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/\"},\"wordCount\":4,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925282\/Web_Assets\/blog\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34.jpg?_i=AA\",\"keywords\":[\"Guest Post\",\"Next.js\",\"React\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/\",\"name\":\"Build an Inventory Tracker\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925282\/Web_Assets\/blog\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34.jpg?_i=AA\",\"datePublished\":\"2022-04-19T17:10:26+00:00\",\"description\":\"Sometimes you need to take a quick look at what you have available, whether it's at a store level or a home level. We're going to build a quick inventory app to handle this for us.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925282\/Web_Assets\/blog\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925282\/Web_Assets\/blog\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34.jpg?_i=AA\",\"width\":3120,\"height\":2080},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Build an Inventory Tracker\"}]},{\"@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":"Build an Inventory Tracker","description":"Sometimes you need to take a quick look at what you have available, whether it's at a store level or a home level. We're going to build a quick inventory app to handle this for us.","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\/build-an-inventory-tracker\/","og_locale":"en_US","og_type":"article","og_title":"Build an Inventory Tracker","og_description":"Sometimes you need to take a quick look at what you have available, whether it's at a store level or a home level. We're going to build a quick inventory app to handle this for us.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-04-19T17:10:26+00:00","og_image":[{"width":3120,"height":2080,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925282\/Web_Assets\/blog\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34.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\/build-an-inventory-tracker\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/"},"author":{"name":"","@id":""},"headline":"Build an Inventory Tracker","datePublished":"2022-04-19T17:10:26+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/"},"wordCount":4,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925282\/Web_Assets\/blog\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34.jpg?_i=AA","keywords":["Guest Post","Next.js","React","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/","name":"Build an Inventory Tracker","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925282\/Web_Assets\/blog\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34.jpg?_i=AA","datePublished":"2022-04-19T17:10:26+00:00","description":"Sometimes you need to take a quick look at what you have available, whether it's at a store level or a home level. We're going to build a quick inventory app to handle this for us.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925282\/Web_Assets\/blog\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925282\/Web_Assets\/blog\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34.jpg?_i=AA","width":3120,"height":2080},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/build-an-inventory-tracker\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Build an Inventory Tracker"}]},{"@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\/v1681925282\/Web_Assets\/blog\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34\/040c3d9811a6879a7edb3496233d6e888701b6c0-3120x2080-1_2815485e34.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28153","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=28153"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28153\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28154"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28153"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28153"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}