search
HomeWeb Front-endCSS TutorialBuilding Production-Grade Web Applications with Supabase – Part 2

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 | }

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>;
}

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 (
...
)
}

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(
    ...
  )
}

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>

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";

And not like:

import TicketList from "./TicketList";

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 | }

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>;
}

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 (
...
)
}

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(
    ...
  )
}

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";

Is replaced with:

import TicketList from "./TicketList";

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.

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 | }

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>
  );
}

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.

And we need to replace:

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

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 | }

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
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
Demystifying Screen Readers: Accessible Forms & Best PracticesDemystifying Screen Readers: Accessible Forms & Best PracticesMar 08, 2025 am 09:45 AM

This is the 3rd post in a small series we did on form accessibility. If you missed the second post, check out "Managing User Focus with :focus-visible". In

Adding Box Shadows to WordPress Blocks and ElementsAdding Box Shadows to WordPress Blocks and ElementsMar 09, 2025 pm 12:53 PM

The CSS box-shadow and outline properties gained theme.json support in WordPress 6.1. Let's look at a few examples of how it works in real themes, and what options we have to apply these styles to WordPress blocks and elements.

Making Your First Custom Svelte TransitionMaking Your First Custom Svelte TransitionMar 15, 2025 am 11:08 AM

The Svelte transition API provides a way to animate components when they enter or leave the document, including custom Svelte transitions.

Working With GraphQL CachingWorking With GraphQL CachingMar 19, 2025 am 09:36 AM

If you’ve recently started working with GraphQL, or reviewed its pros and cons, you’ve no doubt heard things like “GraphQL doesn’t support caching” or

Classy and Cool Custom CSS Scrollbars: A ShowcaseClassy and Cool Custom CSS Scrollbars: A ShowcaseMar 10, 2025 am 11:37 AM

In this article we will be diving into the world of scrollbars. I know, it doesn’t sound too glamorous, but trust me, a well-designed page goes hand-in-hand

Show, Don't TellShow, Don't TellMar 16, 2025 am 11:49 AM

How much time do you spend designing the content presentation for your websites? When you write a new blog post or create a new page, are you thinking about

Building an Ethereum app using Redwood.js and FaunaBuilding an Ethereum app using Redwood.js and FaunaMar 28, 2025 am 09:18 AM

With the recent climb of Bitcoin’s price over 20k $USD, and to it recently breaking 30k, I thought it’s worth taking a deep dive back into creating Ethereum

What the Heck Are npm Commands?What the Heck Are npm Commands?Mar 15, 2025 am 11:36 AM

npm commands run various tasks for you, either as a one-off or a continuously running process for things like starting a server or compiling code.

See all articles

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

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Integrate Eclipse with SAP NetWeaver application server.

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.