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

Building Production-Grade Web Applications with Supabase – Part 2

Barbara Streisand
Barbara StreisandOriginal
2025-01-20 06:09:09850browse

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