Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add organizer to event cards #232

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const resetEvents = async () => {
const data = events25To50Km.map((event) => ({
...event,
creatorId: user.id,
organizedBy: session.user.name,
}));
return await prisma.event.createMany({
data,
Expand Down
2 changes: 2 additions & 0 deletions cypress/e2e/manage-events/add-event.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ describe("Add Event", () => {
cy.get("[data-cy='input-link']").type("https://test.event");
cy.get("[data-cy='input-latitude-add'").type("0");
cy.get("[data-cy='input-longitude-add'").type("0");
cy.get("[data-cy='input-organizedBy'").type("Test Organizer");
cy.get("[data-cy='submit-add-event'").click();

cy.location("pathname").should("eq", "/");
Expand All @@ -29,5 +30,6 @@ describe("Add Event", () => {
// We should only see the event we just created
cy.get("[data-cy='event-card']").should("have.length", 1);
cy.contains("Test Event");
cy.contains("Test Organizer");
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
Warnings:

- Added the required column `organizedBy` to the `Event` table without a default value. This is not possible if the table is not empty.

*/
-- AlterTable
ALTER TABLE "Event" ADD COLUMN "organizedBy" TEXT NOT NULL;
21 changes: 11 additions & 10 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,15 @@ model User {
}

model Event {
id String @id @default(cuid())
name String
date DateTime
link String
latitude Float
longitude Float
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
creator User @relation(fields: [creatorId], references: [id])
creatorId String
id String @id @default(cuid())
name String
date DateTime
link String
latitude Float
longitude Float
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
creator User @relation(fields: [creatorId], references: [id])
organizedBy String
creatorId String
}
2 changes: 1 addition & 1 deletion prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const createEvents = async () => {
const data = events25To50Km.map((event) => ({
...event,
creatorId: user.id,
organizedBy: session.user.name,
}));
await prisma.event.createMany({
data,
Expand All @@ -51,4 +52,3 @@ export const setupDb = async () => {
};

setupDb();

24 changes: 24 additions & 0 deletions src/components/event-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { format } from "date-fns";
import type { EventWithDistance } from "@/types";

export function EventCard({ event }: { event: EventWithDistance }) {
return (
<div data-cy="event-card">
<h2>
Title: <a href={event.link}>{event.name}</a>
</h2>

<p>Organized by: {event.organizedBy}</p>

{/* TODO: replace with a spinner (or similar) to gracefully handle
the delay between receiving the HTML and the browser rendering
the date */}
<p suppressHydrationWarning>
Date: {format(new Date(event.date), "E LLLL d, yyyy @ HH:mm")}
</p>
{event.distance !== null && (
<p>Distance to event: {event.distance.toFixed(2)} km</p>
)}
</div>
);
}
53 changes: 53 additions & 0 deletions src/components/location-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { typeboxResolver } from "@hookform/resolvers/typebox";
import { useForm } from "react-hook-form";
import { Button, Stack } from "@mui/material";
import { type Point, type Feature } from "@turf/helpers";

import { type Location, locationSchema } from "@/validation/schema";
import FormField from "@/components/form-field";

export function LocationForm({
userPosition,
onSubmit,
}: {
userPosition: Feature<Point>;
onSubmit: (data: Location) => void;
}) {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<Location>({
defaultValues: {
latitude: userPosition?.geometry.coordinates[1],
longitude: userPosition?.geometry.coordinates[0],
},
resolver: typeboxResolver(locationSchema),
});

// TODO: DRY this and add-event out, they're almost identical.
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Stack spacing={2}>
<FormField
label="Latitude: "
type="text"
helperText="Latitude must be between -90 and 90 inclusive"
errors={errors}
{...register("latitude", { required: true, valueAsNumber: true })}
/>
<FormField
label="Longitude: "
type="text"
helperText="Longitude must be between -180 and 180 inclusive"
errors={errors}
{...register("longitude", { required: true, valueAsNumber: true })}
/>
<Button data-cy="submit-location" type="submit">
Submit
</Button>
</Stack>
</form>
);
}

8 changes: 8 additions & 0 deletions src/pages/add-event.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ export default function AddEvent() {
{...register("name", { required: true })}
/>

<FormField
type="text"
label="Organized By"
errors={errors}
helperText="Organizer names must be between 1 and 100 characters long"
{...register("organizedBy", { required: true })}
/>

<FormField
type="url"
label="URL"
Expand Down
3 changes: 2 additions & 1 deletion src/pages/api/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,14 @@ const createEvent = async (req: NextApiRequest, res: NextApiResponse) => {
email: user.email,
},
},
organizedBy: req.body.organizedBy,
},
});
} catch (error) {
return res.status(500).json({ message: "Could not create event" });
}

await res.revalidate("/")
await res.revalidate("/");
res.status(200).json({ message: "Event created" });
};

Expand Down
84 changes: 5 additions & 79 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import Head from "next/head";
import { Inter } from "next/font/google";
import { GetStaticProps } from "next";
import { format } from "date-fns";
import { useEffect, useState } from "react";
import distance from "@turf/distance";
import { point, type Point, type Feature } from "@turf/helpers";
import { Button, Stack, Typography } from "@mui/material";
import { typeboxResolver } from "@hookform/resolvers/typebox";
import { Event } from "@prisma/client";
import { useForm } from "react-hook-form";
import { Typography } from "@mui/material";

import { prisma } from "@/db";
import { type Location, locationSchema } from "@/validation/schema";
import FormField from "@/components/form-field";
import { EventCard } from "@/components/event-card";
import { LocationForm } from "@/components/location-form";
import type { EventInfo } from "@/types";

// Given that people can (currently) be assumed to be meeting on the surface of
// the Earth, we can use its circumference to calculate a safe upper bound for
Expand All @@ -21,13 +18,6 @@ const EARTH_CIRCUMFERENCE = "40075.017";

const inter = Inter({ subsets: ["latin"] });

type EventInfo = { date: string } & Omit<
Event,
"createdAt" | "updatedAt" | "creatorId" | "date"
>;

type EventWithDistance = EventInfo & { distance: number | null };

type EventProps = {
events: EventInfo[];
};
Expand All @@ -43,6 +33,7 @@ export const getStaticProps: GetStaticProps<EventProps> = async () => {
link: true,
latitude: true,
longitude: true,
organizedBy: true,
},
});
serializeableEvents = events.map((event) => ({
Expand Down Expand Up @@ -85,71 +76,6 @@ function eventInRadius(
return distanceToEvent ? distanceToEvent <= radius : true;
}

function EventCard({ event }: { event: EventWithDistance }) {
return (
<div data-cy="event-card">
<h2>
Title: <a href={event.link}>{event.name}</a>
</h2>

{/* TODO: replace with a spinner (or similar) to gracefully handle
the delay between receiving the HTML and the browser rendering
the date */}
<p suppressHydrationWarning>
Date: {format(new Date(event.date), "E LLLL d, yyyy @ HH:mm")}
</p>
{event.distance !== null && (
<p>Distance to event: {event.distance.toFixed(2)} km</p>
)}
</div>
);
}

function LocationForm({
userPosition,
onSubmit,
}: {
userPosition: Feature<Point>;
onSubmit: (data: Location) => void;
}) {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<Location>({
defaultValues: {
latitude: userPosition?.geometry.coordinates[1],
longitude: userPosition?.geometry.coordinates[0],
},
resolver: typeboxResolver(locationSchema),
});

// TODO: DRY this and add-event out, they're almost identical.
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Stack spacing={2}>
<FormField
label="Latitude: "
type="text"
helperText="Latitude must be between -90 and 90 inclusive"
errors={errors}
{...register("latitude", { required: true, valueAsNumber: true })}
/>
<FormField
label="Longitude: "
type="text"
helperText="Longitude must be between -180 and 180 inclusive"
errors={errors}
{...register("longitude", { required: true, valueAsNumber: true })}
/>
<Button data-cy="submit-location" type="submit">
Submit
</Button>
</Stack>
</form>
);
}

export default function Home({ events }: EventProps) {
const [userPosition, setUserPosition] = useState<Feature<Point> | null>(null);
const [geoLocationEnabled, setGeoLocationEnabled] = useState(true);
Expand Down
8 changes: 8 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { Event } from "@prisma/client";

export type EventInfo = { date: string } & Omit<
Event,
"createdAt" | "updatedAt" | "creatorId" | "date"
>;

export type EventWithDistance = EventInfo & { distance: number | null };
1 change: 1 addition & 0 deletions src/validation/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const eventSchema = Type.Composite([
name: Type.String({ minLength: 1, maxLength: 100 }),
link: Type.String({ format: "uri" }),
date: Type.String({ format: "date-time" }),
organizedBy: Type.String({ minLength: 1, maxLength: 100}),
}),
locationSchema,
]);
Expand Down
Loading