Getting Started with React, Prisma and NextJs

While not a web developer by trade, I like to periodically try out new frameworks and technologies, plus the trend toward multi-platform applications (e.g. Electron-based) that use web technologies under the hood is hard to ignore.

This article documents my journey with React + Prisma + NextJs.

Project Overview

The goal of this project is a tool for project estimation and quotes for large, multi-discipline, multi-team projects. Most places I've worked have used elaborate Excel spreadsheets and feel there might be a low-cost roll-our-own middle-ground, so this project is intended to demonstrate the concept. On a side note, there are various open-source tools available for software estimation, construction estimate and project management, but doesn't exactly cover hardware / software projects nicely.

Source: https://github.com/ericjameszimmerman/estimatey

Getting started and basic authentication

Largely, I followed along with a basic tutorial for creating the project, building and running it.

I created a tag and release here with the source contained within this section:

https://github.com/ericjameszimmerman/estimatey/releases/tag/v0.1.0

Key Commands

Largely I'm documenting these since I'm likely to forget when switching to other topics.

Build and Run

npm run dev

This builds and runs on localhost:3000, similar to other reactive frameworks.

Prisma Database Migration

npx prisma migrate dev

This connects to the database and modifies the tables according to the current updated models. If it is unable to create a migration file it will let you know. For early development, you can simply purge old tables or data if needed.

Prisma Studio Database Editor

npx prisma studio

Prisma provides a little database editor similar to old MySQL connector or similar tools you may have used in the past.

Milestone 1 - Basic Authentication

The present UI is essentially the same as the tutorial

The "Sign in" page uses the default UI from next-auth. We'll look at adapting that later, but good enough for now.

To test that it did indeed work, I added debug code within the api GET request

If the credentials were invalid, it shows the following:

Milestone 2: Demo CRUD and Rough UI design

This iteration adds functionality to create a project record to the database and view it.

The majority of the following screens are static content that was pillaged from examples but meant to get a feel for the desired functionality.

Takeaways:

  • It took me a little while to get used to, but for api and page structure, I appreciate the react / nextjs approach with folders representing wildcards or ids (e.g. app/api/projects/[id]/route.ts contains the GET request content specific to a specific project id. Similarly, app/projects/[projectid]/page.tsx defines the view displayed when viewing a specific project and app/projects/create/page.tsx defines the project creation view.

  • These frameworks allow freedom to organize files and folders mostly how you please; the trade-off is that it can be difficult to go from a super simple example into something larger and will need to scale.

  • The shadcn/ui examples are pretty nice. I've been using it as a starting point and adapting it to my application.

Demo UI

Here is the super basic form for creating a project.

The following is the UI for the project page. Except for the project name and description, the content is all fake, but imagine that aggregation and a heatmap of the project estimate contents might make up the overview section.

The tab bar is functional and the following shows a data grid, which is likely useful for the top-level list of estimate line items. It is intended that the top-level items may be simple static estimates for some, while others are comprised of another collection of elements, in a hierarchical nature. The item may also be set as a specific type, allowing a software line item to perhaps use points while other categories use different estimation approaches.

Side-note on implementation: it took me a little while to figure out how to fit the data grid into the remaining parent space but scroll. The keys were:

  • change the div containing the tabs from h-full to h-[calc(100vh-74px)] to account for header space.

  • change the top div within data-table.tsx

      # From
      <div className="space-y-4">
      # to
      <div className="flex flex-col h-full">
    
  • change the div within src/registry/new-york/ui/table.tsx from the examples

      # From
      <div className="relative w-full max-h-[400px] overflow-y-scroll">
    
      # to
      <div className="relative w-full table-container h-[calc(100vh-250px)]">
    
  • The following was added to globals.css

    
      .table-container {
        border-radius: 20px;
        padding: 0 10px 10px 10px;
        overflow: scroll;
      }
    
      .table-header {
        position: sticky;
        top: 0px;
        margin: 0 0 0 0;
      }
    

To force the header row to stick to the top, changed the TableHeader within src/registry/new-york/ui/table.tsx:

# From
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />

# to
<thead ref={ref} className={cn("[&_tr]:border-b table-header", className)} {...props} />

References

The following are references that I used when first learning.