Complete "URL Params in Loaders" and "Throwing Responses".
This commit is contained in:
96
src/app/(sidebar)/contacts/[contactId]/Contact.tsx
Normal file
96
src/app/(sidebar)/contacts/[contactId]/Contact.tsx
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ContactRecord } from "@/app/data";
|
||||||
|
import Form from "next/form";
|
||||||
|
import { use } from "react";
|
||||||
|
|
||||||
|
export default function Contact({
|
||||||
|
contact
|
||||||
|
}: {
|
||||||
|
contact: Promise<ContactRecord>
|
||||||
|
}) {
|
||||||
|
const c = use(contact);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id="contact">
|
||||||
|
<div>
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
|
<img
|
||||||
|
alt={`${c.first} ${c.last} avatar`}
|
||||||
|
key={c.avatar}
|
||||||
|
src={c.avatar}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
{c.first || c.last ? (
|
||||||
|
<>
|
||||||
|
{c.first} {c.last}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<i>No Name</i>
|
||||||
|
)}
|
||||||
|
<Favorite contact={c}/>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{c.twitter ? (
|
||||||
|
<p>
|
||||||
|
<a
|
||||||
|
href={`https://twitter.com/${c.twitter}`}
|
||||||
|
>
|
||||||
|
{c.twitter}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{c.notes ? <p>{c.notes}</p> : null}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Form action="edit">
|
||||||
|
<button type="submit">Edit</button>
|
||||||
|
</Form>
|
||||||
|
|
||||||
|
<Form
|
||||||
|
action="destroy"
|
||||||
|
formMethod="post"
|
||||||
|
onSubmit={(event) => {
|
||||||
|
const response = confirm(
|
||||||
|
"Please confirm you want to delete this record."
|
||||||
|
);
|
||||||
|
if (!response) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button type="submit">Delete</button>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Favorite({
|
||||||
|
contact,
|
||||||
|
}: {
|
||||||
|
contact: Pick<ContactRecord, "favorite">;
|
||||||
|
}) {
|
||||||
|
const favorite = contact.favorite;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form action="." formMethod="post">
|
||||||
|
<button
|
||||||
|
aria-label={
|
||||||
|
favorite
|
||||||
|
? "Remove from favorites"
|
||||||
|
: "Add to favorites"
|
||||||
|
}
|
||||||
|
name="favorite"
|
||||||
|
value={favorite ? "false" : "true"}
|
||||||
|
>
|
||||||
|
{favorite ? "★" : "☆"}
|
||||||
|
</button>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
5
src/app/(sidebar)/contacts/[contactId]/loading.tsx
Normal file
5
src/app/(sidebar)/contacts/[contactId]/loading.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export default function ContactLoading() {
|
||||||
|
return (
|
||||||
|
<div>Loading Contact...</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
8
src/app/(sidebar)/contacts/[contactId]/not-found.tsx
Normal file
8
src/app/(sidebar)/contacts/[contactId]/not-found.tsx
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<main id="error-page">
|
||||||
|
<h1>404</h1>
|
||||||
|
<p>The requested contact could not be found.</p>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,98 +1,19 @@
|
|||||||
"use client";
|
import { getContact } from "@/app/data";
|
||||||
|
import { notFound } from "next/navigation";
|
||||||
|
import Contact from "@/app/(sidebar)/contacts/[contactId]/Contact";
|
||||||
|
|
||||||
import Form from "next/form";
|
export default async function ContactPage({
|
||||||
import { ContactRecord } from "@/app/data";
|
params
|
||||||
|
}: {
|
||||||
export default function Contact() {
|
params: Promise<{ contactId: string }>
|
||||||
const contact = {
|
}) {
|
||||||
first: "Your",
|
const { contactId } = await params;
|
||||||
last: "Name",
|
const contact = getContact(contactId).then((c) => {
|
||||||
avatar: "https://placecats.com/200/200",
|
if (c === null) notFound();
|
||||||
twitter: "your_handle",
|
return c;
|
||||||
notes: "Some notes",
|
});
|
||||||
favorite: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="contact">
|
<Contact contact={contact}/>
|
||||||
<div>
|
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
||||||
<img
|
|
||||||
alt={`${contact.first} ${contact.last} avatar`}
|
|
||||||
key={contact.avatar}
|
|
||||||
src={contact.avatar}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h1>
|
|
||||||
{contact.first || contact.last ? (
|
|
||||||
<>
|
|
||||||
{contact.first} {contact.last}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<i>No Name</i>
|
|
||||||
)}
|
|
||||||
<Favorite contact={contact}/>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
{contact.twitter ? (
|
|
||||||
<p>
|
|
||||||
<a
|
|
||||||
href={`https://twitter.com/${contact.twitter}`}
|
|
||||||
>
|
|
||||||
{contact.twitter}
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{contact.notes ? <p>{contact.notes}</p> : null}
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Form action="edit">
|
|
||||||
<button type="submit">Edit</button>
|
|
||||||
</Form>
|
|
||||||
|
|
||||||
<Form
|
|
||||||
action="destroy"
|
|
||||||
formMethod="post"
|
|
||||||
onSubmit={(event) => {
|
|
||||||
const response = confirm(
|
|
||||||
"Please confirm you want to delete this record."
|
|
||||||
);
|
|
||||||
if (!response) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<button type="submit">Delete</button>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Favorite({
|
|
||||||
contact,
|
|
||||||
}: {
|
|
||||||
contact: Pick<ContactRecord, "favorite">;
|
|
||||||
}) {
|
|
||||||
const favorite = contact.favorite;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form action="." formMethod="post">
|
|
||||||
<button
|
|
||||||
aria-label={
|
|
||||||
favorite
|
|
||||||
? "Remove from favorites"
|
|
||||||
: "Add to favorites"
|
|
||||||
}
|
|
||||||
name="favorite"
|
|
||||||
value={favorite ? "false" : "true"}
|
|
||||||
>
|
|
||||||
{favorite ? "★" : "☆"}
|
|
||||||
</button>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user