diff --git a/app/root.tsx b/app/root.tsx index 4b8891e..dc72ca7 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -1,12 +1,40 @@ +import type { LinksFunction } from "@remix-run/node"; import { Form, + Link, Links, Meta, + NavLink, + Outlet, Scripts, ScrollRestoration, + useLoaderData, + useNavigation, } from "@remix-run/react"; +import { redirect } from "@remix-run/node"; + +import appStylesHref from "./app.css?url" +import { getContacts, createEmptyContact } from "./data"; + +export const links: LinksFunction = () => [ + { rel: "stylesheet", href: appStylesHref }, +]; + +export const action = async () => { + const contact = await createEmptyContact(); + return redirect(`/contacts/${contact.id}/edit`) +} + +export const loader = async () => { + const contacts = await getContacts(); + return { contacts }; +}; + export default function App() { + const { contacts } = useLoaderData(); + const navigation = useNavigation(); + return ( @@ -34,16 +62,47 @@ export default function App() { +
+ +
diff --git a/app/routes/contacts.$contactId.tsx b/app/routes/contacts.$contactId.tsx new file mode 100644 index 0000000..b186bb9 --- /dev/null +++ b/app/routes/contacts.$contactId.tsx @@ -0,0 +1,102 @@ +import { Form, useLoaderData } from "@remix-run/react"; +import type { FunctionComponent } from "react"; +import type { LoaderFunctionArgs } from "@remix-run/node"; + +import type { ContactRecord } from "../data"; +import { getContact } from "../data"; +import invariant from "tiny-invariant"; + +export const loader = async ({ + params, + }: LoaderFunctionArgs) => { + invariant(params.contactId, "Missing contactId param"); + const contact = await getContact(params.contactId); + if (!contact) { + throw new Response("Not Found", {status: 404}); + } + return { contact }; + }; + +export default function Contact() { + const { contact } = useLoaderData(); + + return ( +
+
+ {`${contact.first} +
+ +
+

+ {contact.first || contact.last ? ( + <> + {contact.first} {contact.last} + + ) : ( + No Name + )}{" "} + +

+ + {contact.twitter ? ( +

+ + {contact.twitter} + +

+ ) : null} + + {contact.notes ?

{contact.notes}

: null} + +
+
+ +
+ +
{ + const response = confirm( + "Please confirm you want to delete this record." + ); + if (!response) { + event.preventDefault(); + } + }} + > + +
+
+
+
+ ); +} + +const Favorite: FunctionComponent<{ + contact: Pick; +}> = ({ contact }) => { + const favorite = contact.favorite; + + return ( +
+ +
+ ); +}; diff --git a/app/routes/contacts.$contactId_.destroy.tsx b/app/routes/contacts.$contactId_.destroy.tsx new file mode 100644 index 0000000..7610245 --- /dev/null +++ b/app/routes/contacts.$contactId_.destroy.tsx @@ -0,0 +1,13 @@ +import type { ActionFunctionArgs } from "@remix-run/node"; +import { redirect } from "@remix-run/node"; +import invariant from "tiny-invariant"; + +import { deleteContact } from "../data"; + +export const action = async ({ + params, +}: ActionFunctionArgs) => { + invariant(params.contactId, "Missing contactId param"); + await deleteContact(params.contactId); + return redirect("/"); +}; diff --git a/app/routes/contacts.$contactId_.edit.tsx b/app/routes/contacts.$contactId_.edit.tsx new file mode 100644 index 0000000..23a3f1e --- /dev/null +++ b/app/routes/contacts.$contactId_.edit.tsx @@ -0,0 +1,85 @@ +import type { LoaderFunctionArgs, ActionFunctionArgs } from "@remix-run/node"; +import { Form, useLoaderData } from "@remix-run/react"; +import invariant from "tiny-invariant"; + +import { getContact, updateContact } from "../data"; +import { redirect } from "@remix-run/node"; + +export const loader = async ({ + params, +}: LoaderFunctionArgs) => { + invariant(params.contactId, "Missing contactId param"); + const contact = await getContact(params.contactId); + if (!contact) { + throw new Response("Not Found", { status: 404 }); + } + return { contact }; +}; + +export const action = async ({ + params, + request, + }: ActionFunctionArgs) => { + invariant(params.contactId, "Missing contactId param"); + const formData = await request.formData(); + const updates = Object.fromEntries(formData); + await updateContact(params.contactId, updates); + return redirect(`/contacts/${params.contactId}`); + }; + +export default function EditContact() { + const { contact } = useLoaderData(); + + return ( +
+

+ Name + + +

+ + +