Add URL slugs
parent
4d585505f7
commit
a1eed7c77e
|
@ -5,7 +5,7 @@ import prisma from '../lib/prisma';
|
||||||
export default function User(props) {
|
export default function User(props) {
|
||||||
const eventTypes = props.eventTypes.map(type =>
|
const eventTypes = props.eventTypes.map(type =>
|
||||||
<li key={type.id}>
|
<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">
|
<a className="block px-6 py-4">
|
||||||
<div className="inline-block w-3 h-3 rounded-full bg-blue-600 mr-2"></div>
|
<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>
|
<h2 className="inline-block font-medium">{type.title}</h2>
|
||||||
|
|
|
@ -228,6 +228,7 @@ export async function getServerSideProps(context) {
|
||||||
username: context.query.user,
|
username: context.query.user,
|
||||||
},
|
},
|
||||||
select: {
|
select: {
|
||||||
|
id: true,
|
||||||
username: true,
|
username: true,
|
||||||
name: true,
|
name: true,
|
||||||
bio: 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: {
|
where: {
|
||||||
id: parseInt(context.query.type),
|
userId: user.id,
|
||||||
|
slug: {
|
||||||
|
equals: context.query.type,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
|
|
|
@ -24,6 +24,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
if (!user) { res.status(404).json({message: 'User not found'}); return; }
|
if (!user) { res.status(404).json({message: 'User not found'}); return; }
|
||||||
|
|
||||||
const title = req.body.title;
|
const title = req.body.title;
|
||||||
|
const slug = req.body.slug;
|
||||||
const description = req.body.description;
|
const description = req.body.description;
|
||||||
const length = parseInt(req.body.length);
|
const length = parseInt(req.body.length);
|
||||||
const hidden = req.body.hidden;
|
const hidden = req.body.hidden;
|
||||||
|
@ -31,6 +32,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
const createEventType = await prisma.eventType.create({
|
const createEventType = await prisma.eventType.create({
|
||||||
data: {
|
data: {
|
||||||
title: title,
|
title: title,
|
||||||
|
slug: slug,
|
||||||
description: description,
|
description: description,
|
||||||
length: length,
|
length: length,
|
||||||
hidden: hidden,
|
hidden: hidden,
|
||||||
|
@ -56,6 +58,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
|
|
||||||
const id = req.body.id;
|
const id = req.body.id;
|
||||||
const title = req.body.title;
|
const title = req.body.title;
|
||||||
|
const slug = req.body.slug;
|
||||||
const description = req.body.description;
|
const description = req.body.description;
|
||||||
const length = parseInt(req.body.length);
|
const length = parseInt(req.body.length);
|
||||||
const hidden = req.body.hidden;
|
const hidden = req.body.hidden;
|
||||||
|
@ -66,6 +69,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
title: title,
|
title: title,
|
||||||
|
slug: slug,
|
||||||
description: description,
|
description: description,
|
||||||
length: length,
|
length: length,
|
||||||
hidden: hidden
|
hidden: hidden
|
||||||
|
|
|
@ -10,6 +10,7 @@ export default function EventType(props) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [ session, loading ] = useSession();
|
const [ session, loading ] = useSession();
|
||||||
const titleRef = useRef();
|
const titleRef = useRef();
|
||||||
|
const slugRef = useRef();
|
||||||
const descriptionRef = useRef();
|
const descriptionRef = useRef();
|
||||||
const lengthRef = useRef();
|
const lengthRef = useRef();
|
||||||
const isHiddenRef = useRef();
|
const isHiddenRef = useRef();
|
||||||
|
@ -26,6 +27,7 @@ export default function EventType(props) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const enteredTitle = titleRef.current.value;
|
const enteredTitle = titleRef.current.value;
|
||||||
|
const enteredSlug = slugRef.current.value;
|
||||||
const enteredDescription = descriptionRef.current.value;
|
const enteredDescription = descriptionRef.current.value;
|
||||||
const enteredLength = lengthRef.current.value;
|
const enteredLength = lengthRef.current.value;
|
||||||
const enteredIsHidden = isHiddenRef.current.checked;
|
const enteredIsHidden = isHiddenRef.current.checked;
|
||||||
|
@ -34,7 +36,7 @@ export default function EventType(props) {
|
||||||
|
|
||||||
const response = await fetch('/api/availability/eventtype', {
|
const response = await fetch('/api/availability/eventtype', {
|
||||||
method: 'PATCH',
|
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: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'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} />
|
<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>
|
</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">
|
<div className="mb-4">
|
||||||
<label htmlFor="description" className="block text-sm font-medium text-gray-700">Description</label>
|
<label htmlFor="description" className="block text-sm font-medium text-gray-700">Description</label>
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
|
@ -142,6 +162,16 @@ export default function EventType(props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getServerSideProps(context) {
|
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({
|
const eventType = await prisma.eventType.findUnique({
|
||||||
where: {
|
where: {
|
||||||
|
@ -150,6 +180,7 @@ export async function getServerSideProps(context) {
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
title: true,
|
title: true,
|
||||||
|
slug: true,
|
||||||
description: true,
|
description: true,
|
||||||
length: true,
|
length: true,
|
||||||
hidden: true
|
hidden: true
|
||||||
|
@ -158,6 +189,7 @@ export async function getServerSideProps(context) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
|
user,
|
||||||
eventType
|
eventType
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ export default function Availability(props) {
|
||||||
const [successModalOpen, setSuccessModalOpen] = useState(false);
|
const [successModalOpen, setSuccessModalOpen] = useState(false);
|
||||||
const [showChangeTimesModal, setShowChangeTimesModal] = useState(false);
|
const [showChangeTimesModal, setShowChangeTimesModal] = useState(false);
|
||||||
const titleRef = useRef();
|
const titleRef = useRef();
|
||||||
|
const slugRef = useRef();
|
||||||
const descriptionRef = useRef();
|
const descriptionRef = useRef();
|
||||||
const lengthRef = useRef();
|
const lengthRef = useRef();
|
||||||
const isHiddenRef = useRef();
|
const isHiddenRef = useRef();
|
||||||
|
@ -54,6 +55,7 @@ export default function Availability(props) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const enteredTitle = titleRef.current.value;
|
const enteredTitle = titleRef.current.value;
|
||||||
|
const enteredSlug = slugRef.current.value;
|
||||||
const enteredDescription = descriptionRef.current.value;
|
const enteredDescription = descriptionRef.current.value;
|
||||||
const enteredLength = lengthRef.current.value;
|
const enteredLength = lengthRef.current.value;
|
||||||
const enteredIsHidden = isHiddenRef.current.checked;
|
const enteredIsHidden = isHiddenRef.current.checked;
|
||||||
|
@ -62,7 +64,7 @@ export default function Availability(props) {
|
||||||
|
|
||||||
const response = await fetch('/api/availability/eventtype', {
|
const response = await fetch('/api/availability/eventtype', {
|
||||||
method: 'POST',
|
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: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
|
@ -154,7 +156,7 @@ export default function Availability(props) {
|
||||||
{eventType.length} minutes
|
{eventType.length} minutes
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
<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>
|
<Link href={"/availability/event/" + eventType.id}><a className="text-blue-600 hover:text-blue-900">Edit</a></Link>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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" />
|
<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>
|
</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">
|
<div className="mb-4">
|
||||||
<label htmlFor="description" className="block text-sm font-medium text-gray-700">Description</label>
|
<label htmlFor="description" className="block text-sm font-medium text-gray-700">Description</label>
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
|
@ -351,6 +370,7 @@ export async function getServerSideProps(context) {
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
title: true,
|
title: true,
|
||||||
|
slug: true,
|
||||||
description: true,
|
description: true,
|
||||||
length: true,
|
length: true,
|
||||||
hidden: true
|
hidden: true
|
||||||
|
|
|
@ -13,6 +13,7 @@ generator client {
|
||||||
model EventType {
|
model EventType {
|
||||||
id Int @default(autoincrement()) @id
|
id Int @default(autoincrement()) @id
|
||||||
title String
|
title String
|
||||||
|
slug String
|
||||||
description String?
|
description String?
|
||||||
length Int
|
length Int
|
||||||
hidden Boolean @default(false)
|
hidden Boolean @default(false)
|
||||||
|
|
Loading…
Reference in New Issue