Lesson
7
Tidy up the schema and front end code
Tidy up the document form by hiding the old field. Update your front end to only query and access the new field name.
Log in to mark your progress for each Lesson and Task
With the successful content migration, you can now clean up the event document type and the front end query.
For real projects, you can either remove the field completely or add hidden: true
to hide it from content creators, keep its presence in code in cases where legacy data might enter the dataset, and you want to prevent the “unknown field” warning.
Remove the
eventType
field in eventType.ts
or add hidden: true
to hide it visually for content creators.schemaTypes/eventType.ts
defineField({ name: 'eventType', type: 'string', title: 'Event type', deprecated: { reason: 'Use the "Event format" field instead.', }, readOnly: true, hidden: true, // hide from content creators, but keep it in code options: { list: ['in-person', 'virtual'], layout: 'radio', },}),
Remove the
"eventType": coalesce(format, eventType)
line in the GROQ queryReplace the
event.eventType
variable in your front end with the new event.format
variable.Note that if you have used this same front end code for Typed content with Sanity TypeGen your query and components may look a little different. Adapt as required!
src/app/events/[slug]/page.tsx
// From the Next.js code exampleimport { PortableText } from "@portabletext/react";import { SanityDocument } from "next-sanity";import imageUrlBuilder from "@sanity/image-url";
import { SanityImageSource } from "@sanity/image-url/lib/types/types";import { client } from "@/sanity/client";import Link from "next/link";
const EVENT_QUERY = `*[ _type == "event" && slug.current == $slug ][0]{ ..., headline->, venue->}`;
const { projectId, dataset } = client.config();export const urlFor = (source: SanityImageSource) => projectId && dataset ? imageUrlBuilder({ projectId, dataset }).image(source) : null;
export default async function EventPage({ params,}: { params: { slug: string };}) { const event = await client.fetch<SanityDocument>(EVENT_QUERY, params); const { name, date, headline, image, details, format, doorsOpen, venue, tickets, } = event; const eventImageUrl = image?.asset ? urlFor(image)?.url() : null; const artistImageUrl = headline?.photo?.asset ? urlFor(headline.photo)?.url() : null; const eventDate = new Date(date).toDateString(); const eventTime = new Date(date).toLocaleTimeString(); const doorsOpenTime = new Date( new Date(date).getTime() + doorsOpen * 60000 ).toLocaleTimeString();
return ( <main className="w-full min-h-screen py-12 md:py-24 lg:py-32"> <div className="container px-4 md:px-6 mx-auto"> <div className="mb-4"> <Link href="/">← Back to events</Link> </div> <div className="grid items-top gap-6 lg:grid-cols-[1fr_500px] lg:gap-12 xl:grid-cols-[1fr_550px]"> {(eventImageUrl || artistImageUrl) && ( // eslint-disable-next-line @next/next/no-img-element <img alt="Image" className="mx-auto aspect-video overflow-hidden rounded-xl object-cover object-center sm:w-full" height="310" src={eventImageUrl || artistImageUrl || ""} width="550" /> )} <div className="flex flex-col justify-center space-y-4"> <div className="space-y-2"> {format && ( <div className="inline-block rounded-lg bg-gray-100 px-3 py-1 text-sm dark:bg-gray-800 capitalize"> {format.replace("-", " ")} </div> )} {name && ( <h1 className="text-3xl font-bold tracking-tighter sm:text-5xl"> {name} </h1> )} {headline?.name && ( <dl className="grid grid-cols-2 gap-1 text-sm font-medium sm:gap-2 lg:text-base"> <div className="flex items-start"> <dt className="sr-only">Artist</dt> <dd className="font-semibold">Artist</dd> </div> <div className="grid gap-1"> <dt>{headline?.name}</dt> </div> </dl> )} <dl className="grid grid-cols-2 gap-1 text-sm font-medium sm:gap-2 lg:text-base"> <div className="flex items-start"> <dt className="sr-only">Date</dt> <dd className="font-semibold">Date</dd> </div> <div className="grid gap-1"> {eventDate && <dt>{eventDate}</dt>} {eventTime && <dt>{eventTime}</dt>} </div> </dl> {doorsOpenTime && ( <dl className="grid grid-cols-2 gap-1 text-sm font-medium sm:gap-2 lg:text-base"> <div className="flex items-start"> <dt className="sr-only">Doors Open</dt> <dd className="font-semibold">Doors Open</dd> </div> <div className="grid gap-1"> <dt>Doors Open</dt> <dt>{doorsOpenTime}</dt> </div> </dl> )} <dl className="grid grid-cols-2 gap-1 text-sm font-medium sm:gap-2 lg:text-base"> <div className="flex items-start"> <dt className="sr-only">Venue</dt> <dd className="font-semibold">Venue</dd> </div> <div className="grid gap-1"> <dt>{venue.name}</dt> <dt> {venue.city}, {venue.country} </dt> </div> </dl> </div> {details && details.length > 0 && ( <div className="prose max-w-none"> <PortableText value={details} /> </div> )} {tickets && ( <div className="flex gap-4"> <a className="inline-flex h-10 items-center justify-center rounded-md bg-gray-900 w-1/2 text-sm font-medium text-gray-50 shadow transition-colors hover:bg-gray-900/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-gray-950 disabled:pointer-events-none disabled:opacity-50 dark:bg-gray-50 dark:text-gray-900 dark:hover:bg-gray-50/90 dark:focus-visible:ring-gray-300" href={tickets} > Buy Tickets </a> </div> )} </div> </div> </div> </main> );}
You have 3 uncompleted tasks in this lesson
0 of 3