Add URL slugs

pull/115/head
Bailey Pumfleet 2021-04-28 13:24:16 +01:00
parent 4d585505f7
commit a1eed7c77e
6 changed files with 67 additions and 6 deletions

View File

@ -5,7 +5,7 @@ import prisma from '../lib/prisma';
export default function User(props) {
const eventTypes = props.eventTypes.map(type =>
<li key={type.id}>
<Link href={'/' + props.user.username + '/' + type.id.toString()}>
<Link href={'/' + props.user.username + '/' + type.slug}>
<a className="block px-6 py-4">
<div className="inline-block w-3 h-3 rounded-full bg-blue-600 mr-2"></div>
<h2 className="inline-block font-medium">{type.title}</h2>

View File

@ -228,6 +228,7 @@ export async function getServerSideProps(context) {
username: context.query.user,
},
select: {
id: true,
username: true,
name: true,
bio: true,
@ -239,9 +240,12 @@ export async function getServerSideProps(context) {
}
});
const eventType = await prisma.eventType.findUnique({
const eventType = await prisma.eventType.findFirst({
where: {
id: parseInt(context.query.type),
userId: user.id,
slug: {
equals: context.query.type,
},
},
select: {
id: true,

View File

@ -24,6 +24,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
if (!user) { res.status(404).json({message: 'User not found'}); return; }
const title = req.body.title;
const slug = req.body.slug;
const description = req.body.description;
const length = parseInt(req.body.length);
const hidden = req.body.hidden;
@ -31,6 +32,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const createEventType = await prisma.eventType.create({
data: {
title: title,
slug: slug,
description: description,
length: length,
hidden: hidden,
@ -56,6 +58,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const id = req.body.id;
const title = req.body.title;
const slug = req.body.slug;
const description = req.body.description;
const length = parseInt(req.body.length);
const hidden = req.body.hidden;
@ -66,6 +69,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
},
data: {
title: title,
slug: slug,
description: description,
length: length,
hidden: hidden

View File

@ -10,6 +10,7 @@ export default function EventType(props) {
const router = useRouter();
const [ session, loading ] = useSession();
const titleRef = useRef();
const slugRef = useRef();
const descriptionRef = useRef();
const lengthRef = useRef();
const isHiddenRef = useRef();
@ -26,6 +27,7 @@ export default function EventType(props) {
event.preventDefault();
const enteredTitle = titleRef.current.value;
const enteredSlug = slugRef.current.value;
const enteredDescription = descriptionRef.current.value;
const enteredLength = lengthRef.current.value;
const enteredIsHidden = isHiddenRef.current.checked;
@ -34,7 +36,7 @@ export default function EventType(props) {
const response = await fetch('/api/availability/eventtype', {
method: 'PATCH',
body: JSON.stringify({id: props.eventType.id, title: enteredTitle, description: enteredDescription, length: enteredLength, hidden: enteredIsHidden}),
body: JSON.stringify({id: props.eventType.id, title: enteredTitle, slug: enteredSlug, description: enteredDescription, length: enteredLength, hidden: enteredIsHidden}),
headers: {
'Content-Type': 'application/json'
}
@ -75,6 +77,24 @@ export default function EventType(props) {
<input ref={titleRef} type="text" name="title" id="title" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" placeholder="Quick Chat" defaultValue={props.eventType.title} />
</div>
</div>
<div className="mb-4">
<label htmlFor="slug" className="block text-sm font-medium text-gray-700">URL</label>
<div className="mt-1">
<div className="flex rounded-md shadow-sm">
<span className="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 sm:text-sm">
{location.hostname}/{props.user.username}/
</span>
<input
ref={slugRef}
type="text"
name="slug"
id="slug"
className="flex-1 block w-full focus:ring-blue-500 focus:border-blue-500 min-w-0 rounded-none rounded-r-md sm:text-sm border-gray-300"
defaultValue={props.eventType.slug}
/>
</div>
</div>
</div>
<div className="mb-4">
<label htmlFor="description" className="block text-sm font-medium text-gray-700">Description</label>
<div className="mt-1">
@ -142,6 +162,16 @@ export default function EventType(props) {
}
export async function getServerSideProps(context) {
const session = await getSession(context);
const user = await prisma.user.findFirst({
where: {
email: session.user.email,
},
select: {
username: true
}
});
const eventType = await prisma.eventType.findUnique({
where: {
@ -150,6 +180,7 @@ export async function getServerSideProps(context) {
select: {
id: true,
title: true,
slug: true,
description: true,
length: true,
hidden: true
@ -158,6 +189,7 @@ export async function getServerSideProps(context) {
return {
props: {
user,
eventType
},
}

View File

@ -15,6 +15,7 @@ export default function Availability(props) {
const [successModalOpen, setSuccessModalOpen] = useState(false);
const [showChangeTimesModal, setShowChangeTimesModal] = useState(false);
const titleRef = useRef();
const slugRef = useRef();
const descriptionRef = useRef();
const lengthRef = useRef();
const isHiddenRef = useRef();
@ -54,6 +55,7 @@ export default function Availability(props) {
event.preventDefault();
const enteredTitle = titleRef.current.value;
const enteredSlug = slugRef.current.value;
const enteredDescription = descriptionRef.current.value;
const enteredLength = lengthRef.current.value;
const enteredIsHidden = isHiddenRef.current.checked;
@ -62,7 +64,7 @@ export default function Availability(props) {
const response = await fetch('/api/availability/eventtype', {
method: 'POST',
body: JSON.stringify({title: enteredTitle, description: enteredDescription, length: enteredLength, hidden: enteredIsHidden}),
body: JSON.stringify({title: enteredTitle, slug: enteredSlug, description: enteredDescription, length: enteredLength, hidden: enteredIsHidden}),
headers: {
'Content-Type': 'application/json'
}
@ -154,7 +156,7 @@ export default function Availability(props) {
{eventType.length} minutes
</td>
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
{eventType.hidden && <Link href={"/" + props.user.username + "/" + eventType.id}><a className="text-blue-600 hover:text-blue-900 mr-2">View</a></Link>}
{eventType.hidden && <Link href={"/" + props.user.username + "/" + eventType.slug}><a className="text-blue-600 hover:text-blue-900 mr-2">View</a></Link>}
<Link href={"/availability/event/" + eventType.id}><a className="text-blue-600 hover:text-blue-900">Edit</a></Link>
</td>
</tr>
@ -213,6 +215,23 @@ export default function Availability(props) {
<input ref={titleRef} type="text" name="title" id="title" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" placeholder="Quick Chat" />
</div>
</div>
<div className="mb-4">
<label htmlFor="slug" className="block text-sm font-medium text-gray-700">URL</label>
<div className="mt-1">
<div className="flex rounded-md shadow-sm">
<span className="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 sm:text-sm">
{location.hostname}/{props.user.username}/
</span>
<input
ref={slugRef}
type="text"
name="slug"
id="slug"
className="flex-1 block w-full focus:ring-blue-500 focus:border-blue-500 min-w-0 rounded-none rounded-r-md sm:text-sm border-gray-300"
/>
</div>
</div>
</div>
<div className="mb-4">
<label htmlFor="description" className="block text-sm font-medium text-gray-700">Description</label>
<div className="mt-1">
@ -351,6 +370,7 @@ export async function getServerSideProps(context) {
select: {
id: true,
title: true,
slug: true,
description: true,
length: true,
hidden: true

View File

@ -13,6 +13,7 @@ generator client {
model EventType {
id Int @default(autoincrement()) @id
title String
slug String
description String?
length Int
hidden Boolean @default(false)