149 lines
4.3 KiB
TypeScript
149 lines
4.3 KiB
TypeScript
import calendarStyles from "react-big-calendar/lib/css/react-big-calendar.css";
|
|
import calendarOverrides from "../styles/calendar.css";
|
|
import eventStyles from "../styles/events-team.css";
|
|
import { Calendar, dayjsLocalizer } from "react-big-calendar";
|
|
import dayjs from "dayjs";
|
|
import { type LinksFunction } from "@remix-run/cloudflare";
|
|
import {
|
|
Button,
|
|
Container,
|
|
Heading,
|
|
Modal,
|
|
ModalBody,
|
|
ModalCloseButton,
|
|
ModalContent,
|
|
ModalFooter,
|
|
ModalHeader,
|
|
ModalOverlay,
|
|
Text,
|
|
useDisclosure,
|
|
} from "@chakra-ui/react";
|
|
import { useLoaderData } from "@remix-run/react";
|
|
import { useState } from "react";
|
|
import utc from "dayjs/plugin/utc.js";
|
|
|
|
export const links: LinksFunction = () => {
|
|
return [
|
|
{ href: calendarStyles, rel: "stylesheet" },
|
|
{ href: eventStyles, rel: "stylesheet" },
|
|
{ href: calendarOverrides, rel: "stylesheet" },
|
|
];
|
|
};
|
|
|
|
export async function loader({ context }: { context: RequestContext }) {
|
|
if (!context.data.current_user)
|
|
throw new Response(null, {
|
|
status: 401,
|
|
});
|
|
|
|
if (
|
|
![1 << 3, 1 << 4, 1 << 12].find(
|
|
(p) => context.data.current_user.permissions & p,
|
|
)
|
|
)
|
|
throw new Response(null, {
|
|
status: 403,
|
|
});
|
|
|
|
const now = new Date();
|
|
const eventsData = await context.env.D1.prepare(
|
|
"SELECT answer, approved, created_by, day, details, id, month, pending, performed_at, reached_minimum_player_count, type, year FROM events WHERE month = ? AND year = ? ORDER BY day;",
|
|
)
|
|
.bind(now.getUTCMonth() + 1, now.getUTCFullYear())
|
|
.all();
|
|
|
|
if (eventsData.error)
|
|
throw new Response(null, {
|
|
status: 500,
|
|
});
|
|
|
|
const calendarData = eventsData.results.map((e) => {
|
|
return {
|
|
id: e.id,
|
|
title: (e.type as string).toUpperCase(),
|
|
allDay: true,
|
|
// A Date object will not survive being passed to the client
|
|
start: `${e.year}-${(e.month as number).toString().padStart(2, "0")}-${(e.day as number).toString().padStart(2, "0")}T00:00:00.000Z`,
|
|
end: `${e.year}-${(e.month as number).toString().padStart(2, "0")}-${(e.day as number).toString().padStart(2, "0")}T00:00:00.000Z`,
|
|
};
|
|
});
|
|
|
|
const memberData = await context.env.D1.prepare(
|
|
"SELECT id, name FROM et_members WHERE id IN (SELECT created_by FROM events WHERE month = ? AND year = ?);",
|
|
)
|
|
.bind(now.getUTCMonth() + 1, now.getUTCFullYear())
|
|
.all();
|
|
|
|
return {
|
|
calendarData,
|
|
eventList: eventsData.results,
|
|
memberData: memberData.results,
|
|
};
|
|
}
|
|
|
|
export default function () {
|
|
const data = useLoaderData<typeof loader>();
|
|
const [eventData, setEventData] = useState({} as { [k: string]: any });
|
|
const { isOpen, onClose, onOpen } = useDisclosure();
|
|
|
|
dayjs.extend(utc);
|
|
|
|
return (
|
|
<Container maxW="container.lg" h="600px">
|
|
<Modal isOpen={isOpen} onClose={onClose}>
|
|
<ModalOverlay />
|
|
<ModalContent>
|
|
<ModalHeader>Event Info</ModalHeader>
|
|
<ModalCloseButton />
|
|
<ModalBody>
|
|
<Heading size="md">Host</Heading>
|
|
<Text>
|
|
{
|
|
(
|
|
data.memberData.find(
|
|
(m) => m.id === eventData.created_by,
|
|
) as {
|
|
[k: string]: any;
|
|
}
|
|
)?.name
|
|
}
|
|
</Text>
|
|
<br />
|
|
<Heading size="md">Event Type</Heading>
|
|
<Text>{eventData?.type?.toUpperCase()}</Text>
|
|
<br />
|
|
<Heading size="md">Details</Heading>
|
|
<Text>{eventData?.details}</Text>
|
|
<br />
|
|
{eventData?.type === "rotw" ? (
|
|
<>
|
|
<Heading size="md">Answer</Heading>
|
|
<Text>{eventData.answer}</Text>
|
|
</>
|
|
) : null}
|
|
</ModalBody>
|
|
<ModalFooter>
|
|
<Button onClick={onClose}>Close</Button>
|
|
</ModalFooter>
|
|
</ModalContent>
|
|
</Modal>
|
|
<Calendar
|
|
endAccessor={(event) => new Date(event.end)}
|
|
events={data.calendarData}
|
|
localizer={dayjsLocalizer(dayjs)}
|
|
onSelectEvent={(e) => {
|
|
setEventData(
|
|
data.eventList.find((ev) => ev.id === e.id) as { [k: string]: any },
|
|
);
|
|
onOpen();
|
|
}}
|
|
popup
|
|
startAccessor={(event) => new Date(event.start)}
|
|
style={{ height: 500 }}
|
|
toolbar={false}
|
|
views={["month"]}
|
|
/>
|
|
</Container>
|
|
);
|
|
}
|