Home Web Front-end CSS Tutorial Building Production-Grade Web Applications with Supabase – Part 2

Building Production-Grade Web Applications with Supabase – Part 2

Jan 20, 2025 am 06:09 AM

I’m working through David Lorenz’s book Building Production-Grade Web Applications with Supabase (affiliate link) and just finished Chapter 3 – Creating the Ticket Management Pages…. I’ve run into a few issues and thought I’d share them along with how I’ve fixed them.

Section: Setting up Pico.css with Next.js

You can ignore pageProps.children and leave it as children.

Section: Building the login form

Should I really edit app/page.js as LoginPageBuilding Production-Grade Web Applications with Supabase – Part 2

Even though Lorenz explicitly states:

So, open up app/page.js and change the Page component so that it only will return the Login component for now…

I still had to go look for myself the next time I encountered instructions to edit LoginPage. I expected us to create a new page rather than using the existing page.js, but no, wipe everything out in page.js and paste in only the LoginPage code as given in the book.

Error: searchParams should be awaited

Once we update the app/Login.js with the toggling logic (for turning on/off the password field) we start seeing this error:

Error: Route "/" used `searchParams.magicLink`. `searchParams` should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
    at LoginPage (src/app/page.js:3:38)
  1 | import { Login } from "./Login";
  2 | export default function LoginPage({ searchParams }) {
> 3 | const wantsMagicLink = searchParams.magicLink === "yes";
    | ^
  4 | return <login ispasswordlogin="{!wantsMagicLink}"></login>;
  5 | }
Copy after login
Copy after login
Copy after login

To fix this we want to make the LoginPage function in app/page.js asynchronous like so:

import { Login } from "./Login";

export default async function LoginPage({ searchParams }) {
  const params = await searchParams;
  const wantsMagicLink = params.magicLink === "yes";
  return <login ispasswordlogin="{!wantsMagicLink}"></login>;
}
Copy after login
Copy after login

Saving the Username and Password

In the book we are instructed to update our code in Login.js like so:

"use client";
import { useRef } from "react";
export const Login = () => {
const emailInputRef = useRef(null);
const passwordInputRef = useRef(null);
return (
...
)
}
Copy after login
Copy after login

Just in case this isn’t entirely clear, here is what your code should look like:

"use client";
import { useRef } from "react";
import Link from "next/link";

export const Login = ({ isPasswordLogin }) => {
  const emailInputRef = useRef(null);
  const passwordInputRef = useRef(null);

  return(
    ...
  )
}
Copy after login
Copy after login

Where the ... is we aren’t changing anything. Essentially, everything from return( on remains the exact same as before.

The “big thing” I’m pointing out above is that one shouldn’t remove import Link from "next/link"; instead add "use client"; and the useRef import before it.

Side note: Maybe we’ll learn later, but I find it a little odd to use useRef instead of useState here, but then again, I’m not a Next.js or React expert.

Where does that onSubmit event goBuilding Production-Grade Web Applications with Supabase – Part 2

In Login.js within the return( ... ), replace the current

with the form code that includes the onSubmit handler.

Section: Visualizing the Ticket Management UI

Subsection: Creating a shared UI layout with navigation elements

The CSS ex unitBuilding Production-Grade Web Applications with Supabase – Part 2

In the code for app/tickets/TenantName.js Lorenz uses the rarely used CSS ex unit:

<strong>

</strong>
Copy after login

I suspect that this is actually a typo and that Lorenz intended for this to be 1em. While ex is a valid CSS unit it is rarely utilized and is based on the height of the current font. For more on this topic see:

  • W3’s Example Page for EM, PX, PT, CM, IN…
  • W3School’s CSS Units.
  • Perplexity: Should one use the ex CSS unitBuilding Production-Grade Web Applications with Supabase – Part 2

Subsection: Designing the Ticket List Page

Creating dummy tickets whereBuilding Production-Grade Web Applications with Supabase – Part 2

For those who aren’t familiar with React the instruction to add dummyTickets to the page.js file may not be clear enough. You’ll want put these in the TicketListPage() function before the return.

Import howBuilding Production-Grade Web Applications with Supabase – Part 2

Lorenz instructs us to import the TicketList component into page.js. This is pretty straightforward but may be helpful to note that since this is a “named export” we want our import in page.js to look like:

import { TicketList } from "./TicketList";
Copy after login

And not like:

import TicketList from "./TicketList";
Copy after login
Copy after login

If you do the latter you’ll get one of those lovable error messages:

Error: Route "/" used `searchParams.magicLink`. `searchParams` should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
    at LoginPage (src/app/page.js:3:38)
  1 | import { Login } from "./Login";
  2 | export default function LoginPage({ searchParams }) {
> 3 | const wantsMagicLink = searchParams.magicLink === "yes";
    | ^
  4 | return <login ispasswordlogin="{!wantsMagicLink}"></login>;
  5 | }
Copy after login
Copy after login
Copy after login

Subsection: Constructing the Ticket Details page

Error: Route “/tickets/details/[id]” used…

When we follow the instructions for creating the TicketDetailsPage function we will see the following error:

import { Login } from "./Login";

export default async function LoginPage({ searchParams }) {
  const params = await searchParams;
  const wantsMagicLink = params.magicLink === "yes";
  return <login ispasswordlogin="{!wantsMagicLink}"></login>;
}
Copy after login
Copy after login

You may recall that we’ve seen a similar error earlier with the LoginPage function and that we resolved it by making our function async and awaiting the parameter. We’ll do the same here:

"use client";
import { useRef } from "react";
export const Login = () => {
const emailInputRef = useRef(null);
const passwordInputRef = useRef(null);
return (
...
)
}
Copy after login
Copy after login

Error: Route “/tickets/details/[id]” used… (againBuilding Production-Grade Web Applications with Supabase – Part 2)

After updating the /tickets/details/[id]/page.js file (TicketDetailsPage function) we get a very similar error as we did in the last section. What givesBuilding Production-Grade Web Applications with Supabase – Part 2 Simple, we updated our code in the last section but the book doesn’t know that, so the book is still using params.id, simply replace params.id with id and everything should be right as rain.

Subsection: Adding the comments section to the ticket details

The path for the new comments file should be /tickets/details/[id]/TicketComments.js and not /tickets/details[id]/TicketComments.js.

Error: Encountered two children with the same key…

While Next.js doesn’t throw any errors in the terminal output after adding the code that displays the actual comments to TicketComments.js you will see one in the browser:

"use client";
import { useRef } from "react";
import Link from "next/link";

export const Login = ({ isPasswordLogin }) => {
  const emailInputRef = useRef(null);
  const passwordInputRef = useRef(null);

  return(
    ...
  )
}
Copy after login
Copy after login

There are two reasons this occurs. The first is that we aren’t actually using the date as the key, because we have quotes around {comment.date} we are passing in the string literal comment.date. To fix this we need to remove the quotes so that this:





I suspect that this is actually a typo and that Lorenz intended for this to be 1em. While ex is a valid CSS unit it is rarely utilized and is based on the height of the current font. For more on this topic see:

  • W3’s Example Page for EM, PX, PT, CM, IN…
  • W3School’s CSS Units.
  • Perplexity: Should one use the ex CSS unitBuilding Production-Grade Web Applications with Supabase – Part 2

Subsection: Designing the Ticket List Page

Creating dummy tickets whereBuilding Production-Grade Web Applications with Supabase – Part 2

For those who aren’t familiar with React the instruction to add dummyTickets to the page.js file may not be clear enough. You’ll want put these in the TicketListPage() function before the return.

Import howBuilding Production-Grade Web Applications with Supabase – Part 2

Lorenz instructs us to import the TicketList component into page.js. This is pretty straightforward but may be helpful to note that since this is a “named export” we want our import in page.js to look like:

import { TicketList } from "./TicketList";
Copy after login

Is replaced with:

import TicketList from "./TicketList";
Copy after login
Copy after login

Once this is done we won’t get that error anymore but we should note that there is another issue, even if it isn’t apparent at the moment. What happens if two or more individuals comment on the same dateBuilding Production-Grade Web Applications with Supabase – Part 2 Our keys again aren’t unique and we’ll see this same error. We can fix this quickly by adding an id property to our comments. Our updated comments should now look like:

./src/app/tickets/page.js:1:1 Export default doesn't exist in target module

1 | import TicketList from "./TicketList"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
2 | 
3 | export default function TicketListPage() { 4 | const dummyTickets = [

The export default was not found in module [project]/src/app/tickets/TicketList.js [app-rsc] (ecmascript). Did you mean to import TicketListBuilding Production-Grade Web Applications with Supabase – Part 2 All exports of the module are statically known (It doesn't have dynamic exports). So it's known statically that the requested export doesn't exist.
Copy after login

Then we just need to change:

Error: Route "/tickets/details/[id]" used `params.id`. `params` should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
    at TicketDetailsPage (src/app/tickets/details/[id]/page.js:4:50)
  2 | return (
  3 | <div>
> 4 | Ticket Details page with <strong>ID={params.id}</strong>
    | ^
  5 | </div>
  6 | );
  7 | }
Copy after login

To:

export default async function TicketDetailsPage({ params }) {
  const ticketParams = await params;
  const id = ticketParams.id;

  return (
    <div>
      Ticket Details page with <strong>ID={id}</strong>
    </div>
  );
}
Copy after login

Subsection: Implementing a page to create a new ticket

Nothing to see here folks.

Subsection: Implementing a user overview

Getting the Icons Installed

We need to install the @tabler/icons-react package: npm i @tabler/icons-react

While Lorenz uses IconCheck I’d recommend using IconUserCheck as it’s a little clearer what one is displaying.

We need to import the IconUserCheck and IconUserOff components in our users/page.js:

Encountered two children with the same key, `{comment.date}`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
Copy after login

And we need to replace:

<article key="{comment.date}">
</article>
Copy after login

With:

Error: Route "/" used `searchParams.magicLink`. `searchParams` should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
    at LoginPage (src/app/page.js:3:38)
  1 | import { Login } from "./Login";
  2 | export default function LoginPage({ searchParams }) {
> 3 | const wantsMagicLink = searchParams.magicLink === "yes";
    | ^
  4 | return <login ispasswordlogin="{!wantsMagicLink}"></login>;
  5 | }
Copy after login
Copy after login
Copy after login

Change the pathname === "/tickets" to whichever page the link is pointing at, e.g. if the link points to /tickets/new then you should set the pathname section to pathname === "/tickets/new".

The Conclusion

Congratulations, you are now person #3 that is interested in this post. Building Production-Grade Web Applications with Supabase – Part 2

The above is the detailed content of Building Production-Grade Web Applications with Supabase – Part 2. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Vue 3 Vue 3 Apr 02, 2025 pm 06:32 PM

It&#039;s out! Congrats to the Vue team for getting it done, I know it was a massive effort and a long time coming. All new docs, as well.

Can you get valid CSS property values from the browser? Can you get valid CSS property values from the browser? Apr 02, 2025 pm 06:17 PM

I had someone write in with this very legit question. Lea just blogged about how you can get valid CSS properties themselves from the browser. That&#039;s like this.

A bit on ci/cd A bit on ci/cd Apr 02, 2025 pm 06:21 PM

I&#039;d say "website" fits better than "mobile app" but I like this framing from Max Lynch:

Stacked Cards with Sticky Positioning and a Dash of Sass Stacked Cards with Sticky Positioning and a Dash of Sass Apr 03, 2025 am 10:30 AM

The other day, I spotted this particularly lovely bit from Corey Ginnivan’s website where a collection of cards stack on top of one another as you scroll.

Using Markdown and Localization in the WordPress Block Editor Using Markdown and Localization in the WordPress Block Editor Apr 02, 2025 am 04:27 AM

If we need to show documentation to the user directly in the WordPress editor, what is the best way to do it?

Comparing Browsers for Responsive Design Comparing Browsers for Responsive Design Apr 02, 2025 pm 06:25 PM

There are a number of these desktop apps where the goal is showing your site at different dimensions all at the same time. So you can, for example, be writing

Why are the purple slashed areas in the Flex layout mistakenly considered 'overflow space'? Why are the purple slashed areas in the Flex layout mistakenly considered 'overflow space'? Apr 05, 2025 pm 05:51 PM

Questions about purple slash areas in Flex layouts When using Flex layouts, you may encounter some confusing phenomena, such as in the developer tools (d...

How to select a child element with the first class name item through CSS? How to select a child element with the first class name item through CSS? Apr 05, 2025 pm 11:24 PM

When the number of elements is not fixed, how to select the first child element of the specified class name through CSS. When processing HTML structure, you often encounter different elements...

See all articles