mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-14 07:06:14 -05:00
event info
This commit is contained in:
@@ -1,27 +1,85 @@
|
||||
import { Button } from "@chakra-ui/button";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { useState } from "react";
|
||||
import { Input } from "@chakra-ui/input";
|
||||
import { Box } from "@chakra-ui/layout";
|
||||
import { t, Trans } from "@lingui/macro";
|
||||
import SubText from "components/common/SubText";
|
||||
import { useMyTheme } from "hooks/common";
|
||||
import { Fragment, useState } from "react";
|
||||
import { trpc } from "utils/trpc";
|
||||
import EventInfo from "./EventInfo";
|
||||
import { EventModal } from "./EventModal";
|
||||
|
||||
export default function CalendarPage() {
|
||||
const { gray } = useMyTheme();
|
||||
const events = trpc.useQuery(["calendar.events"], { enabled: false });
|
||||
const [modalIsOpen, setModalIsOpen] = useState(false);
|
||||
const [filter, setFilter] = useState("");
|
||||
|
||||
console.log("events", events.data);
|
||||
|
||||
let lastPrintedWeek: number | null = null;
|
||||
const thisWeekNumber = getWeekNumber(new Date());
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button size="sm" onClick={() => setModalIsOpen(true)}>
|
||||
<Trans>Add event</Trans>
|
||||
</Button>
|
||||
{modalIsOpen && (
|
||||
<EventModal
|
||||
onClose={() => setModalIsOpen(false)}
|
||||
event={false}
|
||||
refetchQuery={events.refetch}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<>
|
||||
<div>
|
||||
<Button size="sm" onClick={() => setModalIsOpen(true)}>
|
||||
<Trans>Add event</Trans>
|
||||
</Button>
|
||||
{modalIsOpen && (
|
||||
<EventModal
|
||||
onClose={() => setModalIsOpen(false)}
|
||||
event={false}
|
||||
refetchQuery={events.refetch}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Input
|
||||
value={filter}
|
||||
onChange={(e) => setFilter(e.target.value)}
|
||||
m="3rem 0 2rem"
|
||||
/>
|
||||
{(events.data ?? []).map((event) => {
|
||||
const weekNumber = getWeekNumber(event.date);
|
||||
const printWeekHeader = weekNumber !== lastPrintedWeek;
|
||||
|
||||
if (printWeekHeader) {
|
||||
lastPrintedWeek = weekNumber;
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment key={event.id}>
|
||||
{printWeekHeader && (
|
||||
<Box my={10}>
|
||||
<SubText>
|
||||
Week {weekNumber}{" "}
|
||||
{thisWeekNumber === weekNumber && <>({t`This week`})</>}
|
||||
</SubText>
|
||||
</Box>
|
||||
)}
|
||||
<div>
|
||||
<EventInfo event={event} />
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
<Box color={gray}>All events listed in your local time:</Box>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function getWeekNumber(d: Date) {
|
||||
// Copy date so don't modify original
|
||||
d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
|
||||
// Set to nearest Thursday: current date + 4 - current day number
|
||||
// Make Sunday's day number 7
|
||||
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
|
||||
// Get first day of year
|
||||
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
||||
// Calculate full weeks to nearest Thursday
|
||||
const weekNo = Math.ceil(
|
||||
((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7
|
||||
);
|
||||
// Return array of year and week number
|
||||
return weekNo;
|
||||
}
|
||||
|
||||
122
app/calendar/components/EventInfo.tsx
Normal file
122
app/calendar/components/EventInfo.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
import { Box, Button, Flex, Grid, Heading } from "@chakra-ui/react";
|
||||
import Markdown from "components/common/Markdown";
|
||||
import MyLink from "components/common/MyLink";
|
||||
import UserAvatar from "components/common/UserAvatar";
|
||||
import { useMyTheme, useUser } from "hooks/common";
|
||||
import React, { useState } from "react";
|
||||
import { FaDiscord } from "react-icons/fa";
|
||||
import { FiClock, FiEdit, FiInfo } from "react-icons/fi";
|
||||
import { ADMIN_ID } from "utils/constants";
|
||||
import { Unpacked } from "utils/types";
|
||||
import { Events } from "../service";
|
||||
|
||||
interface EventInfoProps {
|
||||
event: Unpacked<Events>;
|
||||
}
|
||||
|
||||
const TournamentInfo = ({ event }: EventInfoProps) => {
|
||||
const {
|
||||
secondaryBgColor,
|
||||
themeColorHex,
|
||||
gray,
|
||||
themeColorShade,
|
||||
} = useMyTheme();
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const poster = event.poster;
|
||||
|
||||
const [user] = useUser();
|
||||
|
||||
const canEdit = user?.id === poster.id || user?.id === ADMIN_ID;
|
||||
|
||||
return (
|
||||
<Box
|
||||
as="section"
|
||||
rounded="lg"
|
||||
overflow="hidden"
|
||||
boxShadow="md"
|
||||
bg={secondaryBgColor}
|
||||
p="20px"
|
||||
my={5}
|
||||
>
|
||||
<Box textAlign="center">
|
||||
<Box>
|
||||
<Heading fontFamily="'Rubik', sans-serif" size="lg">
|
||||
{event.name}
|
||||
</Heading>
|
||||
<Flex
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
color={gray}
|
||||
mt="0.5rem"
|
||||
>
|
||||
<Box as={FiClock} mr="0.5em" color={themeColorShade} />
|
||||
{/* TODO */}
|
||||
{event.date.toLocaleString("en", {
|
||||
weekday: "long",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})}
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
color={gray}
|
||||
mt="1.1rem"
|
||||
mb="0.5rem"
|
||||
>
|
||||
<Box mr="0.5em">
|
||||
<UserAvatar user={event.poster} size="sm" />
|
||||
</Box>{" "}
|
||||
<MyLink href={`/u/${poster.discordId}`} isColored={false}>
|
||||
<Box>
|
||||
{poster.username}#{poster.discriminator}
|
||||
</Box>
|
||||
</MyLink>
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
<Grid
|
||||
templateColumns={canEdit ? "1fr 1fr 1fr" : "1fr 1fr"}
|
||||
gridColumnGap="1rem"
|
||||
maxW={canEdit ? "32rem" : "24rem"}
|
||||
mx="auto"
|
||||
mt={6}
|
||||
>
|
||||
{/* TODO */}
|
||||
<Button leftIcon={<FaDiscord />} size="sm" variant="outline">
|
||||
Join Discord
|
||||
</Button>
|
||||
<Button
|
||||
leftIcon={<FiInfo />}
|
||||
size="sm"
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
variant="outline"
|
||||
>
|
||||
View info
|
||||
</Button>
|
||||
{canEdit && (
|
||||
<Button
|
||||
leftIcon={<FiEdit />}
|
||||
size="sm"
|
||||
onClick={() => setShowModal(true)}
|
||||
variant="outline"
|
||||
>
|
||||
Edit event
|
||||
</Button>
|
||||
)}
|
||||
</Grid>
|
||||
</Box>
|
||||
{expanded && (
|
||||
<Box mt="1rem" mx="0.5rem">
|
||||
<Markdown value={event.description} />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default TournamentInfo;
|
||||
@@ -1,9 +1,15 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import prisma from "prisma/client";
|
||||
import { eventSchema } from "utils/validators/event";
|
||||
import * as z from "zod";
|
||||
|
||||
export type Events = Prisma.PromiseReturnType<typeof events>;
|
||||
|
||||
const events = () => {
|
||||
return prisma.calendarEvent.findMany({ where: { date: { gt: new Date() } } });
|
||||
return prisma.calendarEvent.findMany({
|
||||
where: { date: { gt: new Date() } },
|
||||
include: { poster: true },
|
||||
});
|
||||
};
|
||||
|
||||
const addEvent = async ({
|
||||
|
||||
Reference in New Issue
Block a user