mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-25 07:32:19 -05:00
Share types between backend and frontend
This commit is contained in:
parent
e7bf162ab9
commit
90408ca7f9
7419
package-lock.json
generated
7419
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
|
@ -1,8 +1,10 @@
|
|||
{
|
||||
"name": "sendou.ink",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"packages/server",
|
||||
"packages/frontend"
|
||||
"packages/frontend",
|
||||
"packages/api"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
1
packages/api/index.ts
Normal file
1
packages/api/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./tournaments.api";
|
||||
4
packages/api/package.json
Normal file
4
packages/api/package.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "@sendou-ink/api",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
14
packages/api/tournaments.api.ts
Normal file
14
packages/api/tournaments.api.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
export interface GetTournamentByOrganizationAndName {
|
||||
name: string;
|
||||
desription: string | null;
|
||||
startTime: Date;
|
||||
checkInTime: Date;
|
||||
bannerBackground: string;
|
||||
bannerTextColor: string;
|
||||
organizer: {
|
||||
name: string;
|
||||
discordInvite: string;
|
||||
twitter: string | null;
|
||||
nameForUrl: string;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import styled from "@emotion/styled";
|
||||
import { ReactNode } from "react";
|
||||
import { FaDiscord, FaTwitter } from "react-icons/fa";
|
||||
import { useTournamentData } from "../../hooks/data/useTournamentData";
|
||||
|
||||
const infos = [
|
||||
{
|
||||
|
|
@ -91,37 +91,6 @@ const _IconButtons = styled.div`
|
|||
gap: 1rem;
|
||||
`;
|
||||
|
||||
export function InfoBanner() {
|
||||
return (
|
||||
<_Container>
|
||||
<_TopRow>
|
||||
<_DateName>
|
||||
<_MonthDate>
|
||||
<_Month>APR</_Month>
|
||||
<_Date>23</_Date>
|
||||
</_MonthDate>
|
||||
<_TournamentName>In The Zone 23</_TournamentName>
|
||||
</_DateName>
|
||||
<_IconButtons>
|
||||
<IconButton href="https://twitter.com/sendouc">
|
||||
<FaTwitter />
|
||||
</IconButton>
|
||||
<IconButton href="https://discord.gg/sendou">
|
||||
<FaDiscord />
|
||||
</IconButton>
|
||||
</_IconButtons>
|
||||
</_TopRow>
|
||||
<_BottomRow>
|
||||
<_Infos>
|
||||
{infos.map((info) => (
|
||||
<Info key={info.title} info={info} />
|
||||
))}
|
||||
</_Infos>
|
||||
</_BottomRow>
|
||||
</_Container>
|
||||
);
|
||||
}
|
||||
|
||||
const _InfoContainer = styled.div`
|
||||
font-size: var(--fonts-xs);
|
||||
|
||||
|
|
@ -130,15 +99,6 @@ const _InfoContainer = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
function Info(props: { info: { title: string; value: string } }) {
|
||||
return (
|
||||
<_InfoContainer>
|
||||
<label>{props.info.title}</label>
|
||||
<div>{props.info.value}</div>
|
||||
</_InfoContainer>
|
||||
);
|
||||
}
|
||||
|
||||
const _IconButton = styled.a`
|
||||
display: inline-flex;
|
||||
width: 2.25rem;
|
||||
|
|
@ -159,6 +119,44 @@ const _IconButton = styled.a`
|
|||
}
|
||||
`;
|
||||
|
||||
function IconButton(props: { children: ReactNode; href: string }) {
|
||||
return <_IconButton href={props.href}>{props.children}</_IconButton>;
|
||||
export function InfoBanner() {
|
||||
const { data } = useTournamentData();
|
||||
|
||||
// TODO: handle loading
|
||||
// TODO: handle error in parent
|
||||
if (!data) return null;
|
||||
|
||||
return (
|
||||
<_Container>
|
||||
<_TopRow>
|
||||
<_DateName>
|
||||
<_MonthDate>
|
||||
<_Month>APR</_Month>
|
||||
<_Date>23</_Date>
|
||||
</_MonthDate>
|
||||
<_TournamentName>{data.name}</_TournamentName>
|
||||
</_DateName>
|
||||
<_IconButtons>
|
||||
{data.organizer.twitter && (
|
||||
<_IconButton href={data.organizer.twitter}>
|
||||
<FaTwitter />
|
||||
</_IconButton>
|
||||
)}
|
||||
<_IconButton href={data.organizer.discordInvite}>
|
||||
<FaDiscord />
|
||||
</_IconButton>
|
||||
</_IconButtons>
|
||||
</_TopRow>
|
||||
<_BottomRow>
|
||||
<_Infos>
|
||||
{infos.map((info) => (
|
||||
<_InfoContainer>
|
||||
<label>{info.title}</label>
|
||||
<div>{info.value}</div>
|
||||
</_InfoContainer>
|
||||
))}
|
||||
</_Infos>
|
||||
</_BottomRow>
|
||||
</_Container>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
15
packages/frontend/hooks/data/useTournamentData.ts
Normal file
15
packages/frontend/hooks/data/useTournamentData.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import useSWR from "swr";
|
||||
import type { GetTournamentByOrganizationAndName } from "@sendou-ink/api";
|
||||
import { useRouter } from "next/dist/client/router";
|
||||
|
||||
export function useTournamentData() {
|
||||
const router = useRouter();
|
||||
const { organization, tournament } = router.query;
|
||||
const result = useSWR<GetTournamentByOrganizationAndName>(
|
||||
typeof organization === "string" && typeof tournament === "string"
|
||||
? `/tournaments/${organization}/${tournament}`
|
||||
: null
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,13 +1,5 @@
|
|||
import { useRouter } from "next/dist/client/router";
|
||||
import useSWR from "swr";
|
||||
import { InfoBanner } from "../../../components/tournament/InfoBanner";
|
||||
|
||||
export default function TournamentPage() {
|
||||
const router = useRouter();
|
||||
const { data, error } = useSWR(
|
||||
router.query.organization && router.query.tournament
|
||||
? `/tournaments/${router.query.organization}/${router.query.tournament}`
|
||||
: null
|
||||
);
|
||||
return <InfoBanner />;
|
||||
}
|
||||
|
|
|
|||
4
packages/server/package-lock.json
generated
4
packages/server/package-lock.json
generated
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "server.sendou.ink",
|
||||
"name": "@sendou.ink/server",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "server.sendou.ink",
|
||||
"name": "@sendou.ink/server",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@prisma/client": "^3.3.0",
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import { App } from "@tinyhttp/app";
|
||||
import { findTournamentByNameForUrl } from "../services/tournament";
|
||||
import type { GetTournamentByOrganizationAndName } from "@sendou-ink/api";
|
||||
|
||||
const app = new App();
|
||||
|
||||
app.get("/:organization/:tournament", async (req, res) => {
|
||||
const { organization, tournament } = req.params;
|
||||
const tournamentFromDB = await findTournamentByNameForUrl({
|
||||
organizationNameForUrl: organization,
|
||||
tournamentNameForUrl: tournament,
|
||||
});
|
||||
const tournamentFromDB: GetTournamentByOrganizationAndName | undefined =
|
||||
await findTournamentByNameForUrl({
|
||||
organizationNameForUrl: organization,
|
||||
tournamentNameForUrl: tournament,
|
||||
});
|
||||
|
||||
if (!tournamentFromDB) return res.sendStatus(404);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,21 @@ export async function findTournamentByNameForUrl({
|
|||
where: {
|
||||
nameForUrl: tournamentNameForUrl.toLowerCase(),
|
||||
},
|
||||
include: {
|
||||
organizer: true,
|
||||
select: {
|
||||
name: true,
|
||||
desription: true,
|
||||
startTime: true,
|
||||
checkInTime: true,
|
||||
bannerBackground: true,
|
||||
bannerTextColor: true,
|
||||
organizer: {
|
||||
select: {
|
||||
name: true,
|
||||
discordInvite: true,
|
||||
twitter: true,
|
||||
nameForUrl: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user