-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
315 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { z } from "zod"; | ||
import { marked } from "marked"; | ||
|
||
const EventSchema = z.object({ | ||
id: z.number(), | ||
name: z.string(), | ||
slug: z.string(), | ||
date: z.string(), | ||
content: z.string().transform((content) => marked(content)), | ||
results: z.boolean() | ||
}); | ||
|
||
export type Event = z.infer<typeof EventSchema>; | ||
|
||
|
||
export async function getLatestEventsAndResults() { | ||
const [events, results] = await Promise.all([ | ||
getEvents({ results: false, limit: 5 }).then((res) => { | ||
return res.filter((event) => { | ||
return new Date(event.date) >= | ||
new Date(); | ||
}); | ||
}), | ||
getEvents({ results: true, limit: 5 }), | ||
]); | ||
return { | ||
events, | ||
results | ||
} | ||
} | ||
|
||
export function getEvents({ | ||
results, | ||
limit, | ||
}: { | ||
limit?: number; | ||
results: boolean; | ||
}) { | ||
return fetch( | ||
`${process.env.STRAPI_URL}/api/veranstaltungs?sort[0]=date:desc&populate=*&filters[results][$eq]=${results}&pagination[limit]=${limit}` | ||
).then((res) => res.json()).then((res) => { | ||
const events = res.data.map((data: unknown) => { | ||
const event = EventSchema.safeParse(data) | ||
if(event.success) { | ||
return event.data; | ||
} | ||
return null; | ||
}).filter((event: Event | null) => event !== null) as Event[]; | ||
return events; | ||
}); | ||
} | ||
|
||
export function getEvent({ slug }: { slug: string }) { | ||
return fetch(` | ||
${process.env.STRAPI_URL}/api/veranstaltungs?sort[0]=date:desc&populate=*&filters[slug][$eq]=${slug}` | ||
).then((res) => res.json()).then((res) => { | ||
const event = z.array(EventSchema).min(1).max(1).safeParse(res.data); | ||
if(event.success) { | ||
return event.data[0]; | ||
} | ||
throw new Response("Veranstaltung existiert nicht", { | ||
status: 404, | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import type { MetaFunction } from "@remix-run/node"; | ||
import { json } from "@remix-run/node"; | ||
import { Link, useLoaderData } from "@remix-run/react"; | ||
import { getEvents } from "~/.server/events"; | ||
import ContentContainer from "~/components/ContentContainer"; | ||
import Title from "~/components/Title"; | ||
|
||
export const meta: MetaFunction = () => { | ||
return [ | ||
{ | ||
title: "Wettkampfergebnisse", | ||
} | ||
] | ||
}; | ||
|
||
export async function loader() { | ||
const results = await getEvents({ results: true }).then((res) => { | ||
return res.sort((a, b) => { | ||
return new Date(a.date).getTime() - new Date(b.date).getTime(); | ||
}); | ||
}); | ||
const years: number[] = []; | ||
results | ||
.forEach((result) => { | ||
const year = new Date(result.date).getFullYear(); | ||
if (!years.includes(year)) { | ||
years.push(year); | ||
} | ||
}); | ||
return json({ | ||
results: results.reverse(), | ||
years: years.reverse(), | ||
}); | ||
} | ||
|
||
export default function ResultPage() { | ||
const { results, years } = useLoaderData<typeof loader>(); | ||
return ( | ||
<ContentContainer> | ||
<Title name="Wettkampfergebnisse" /> | ||
<div className="w-full overflow-x-auto"> | ||
<table className="whitespace-no-wrap w-full"> | ||
{years.map((year) => ( | ||
<tbody key={year} className="divide-y bg-white"> | ||
<tr> | ||
<td> | ||
<p className="text-bold my-4 max-w-min rounded-md p-3 text-3xl "> | ||
{year} | ||
</p> | ||
</td> | ||
</tr> | ||
{results | ||
.filter( | ||
(result) => new Date(result.date).getFullYear() === year | ||
) | ||
.map((result, index) => ( | ||
<tr key={index} className="text-gray-700 even:bg-gray-300"> | ||
<td className="px-4 py-3"> | ||
<time className="font-semibold"> | ||
{new Date(result.date).toLocaleDateString("de-DE", { | ||
timeZone: "Europe/Berlin", | ||
year: "numeric", | ||
month: "2-digit", | ||
day: "2-digit", | ||
})} | ||
</time> | ||
</td> | ||
<td className="px-4 py-3"> | ||
<p>{result.name}</p> | ||
</td> | ||
<td className="px-4 py-3"> | ||
<Link to={`/veranstaltungen/${result.slug}`}> | ||
<svg | ||
xmlns="http://www.w3.org/2000/svg" | ||
className="h-4 w-4 md:h-6 md:w-6" | ||
viewBox="0 0 512 512" | ||
> | ||
<path d="M480.6 341.4c-11.3 0-20.4 9.1-20.4 20.4v98.4H51.8v-98.4c0-11.3-9.1-20.4-20.4-20.4-11.3 0-20.4 9.1-20.4 20.4v118.8c0 11.3 9.1 20.4 20.4 20.4h449.2c11.3 0 20.4-9.1 20.4-20.4V361.8c0-11.3-9.1-20.4-20.4-20.4z" /> | ||
<path d="M241 365.6c11.5 11.6 25.6 5.2 29.9 0l117.3-126.2c7.7-8.3 7.2-21.2-1.1-28.9-8.3-7.7-21.2-7.2-28.8 1.1l-81.9 88.1V34.5c0-11.3-9.1-20.4-20.4-20.4-11.3 0-20.4 9.1-20.4 20.4v265.3l-81.9-88.1c-7.7-8.3-20.6-8.7-28.9-1.1-8.3 7.7-8.7 20.6-1.1 28.9L241 365.6z" /> | ||
</svg> | ||
</Link> | ||
</td> | ||
</tr> | ||
))} | ||
</tbody> | ||
))} | ||
</table> | ||
</div> | ||
</ContentContainer> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import ContentContainer from "~/components/ContentContainer"; | ||
import Title from "~/components/Title"; | ||
|
||
import Component from "~/assets/sport-konzept.mdx"; | ||
import type { MetaFunction } from "@remix-run/node"; | ||
|
||
export const meta: MetaFunction = () => { | ||
return [ | ||
{ | ||
title: "Nachwuchs- und Leistungssportkonzept", | ||
} | ||
] | ||
}; | ||
|
||
export default function Page() { | ||
return ( | ||
<ContentContainer className="gap-4"> | ||
<Title name="Nachwuchs- und Leistungssportkonzept" /> | ||
<div className="prose max-w-none text-left"> | ||
<Component /> | ||
</div> | ||
</ContentContainer> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { json, LoaderFunctionArgs } from "@remix-run/node"; | ||
import { useLoaderData } from "@remix-run/react"; | ||
import { getEvent } from "~/.server/events"; | ||
import ContentContainer from "~/components/ContentContainer"; | ||
|
||
export async function loader({ params }: LoaderFunctionArgs) { | ||
const event = await getEvent({ slug: params.slug ? params.slug : "" }); | ||
return json({ | ||
event, | ||
}); | ||
} | ||
|
||
export default function AthleteProfilePage() { | ||
const { event } = useLoaderData<typeof loader>(); | ||
return ( | ||
<ContentContainer className="gap-4"> | ||
<h1 className="text-left text-3xl font-bold">{event.name}</h1> | ||
<time className="text-left font-semibold"> | ||
{new Date(event.date).toLocaleDateString("de-DE", { | ||
timeZone: "Europe/Berlin", | ||
year: "numeric", | ||
month: "2-digit", | ||
day: "2-digit", | ||
})} | ||
</time> | ||
{event.content ? ( | ||
<div | ||
className="prose prose-lg max-w-none text-left" | ||
dangerouslySetInnerHTML={{ __html: event.content }} | ||
/> | ||
) : ( | ||
<p className="font-medium"> | ||
Noch keine weiteren Informationen vorhanden | ||
</p> | ||
)} | ||
</ContentContainer> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import type { MetaFunction } from "@remix-run/node"; | ||
import { json } from "@remix-run/node"; | ||
import { useLoaderData } from "@remix-run/react"; | ||
import { getEvents } from "~/.server/events"; | ||
import ContentContainer from "~/components/ContentContainer"; | ||
import Title from "~/components/Title"; | ||
import EventCard from "~/components/pages/veranstaltungen/EventCard"; | ||
|
||
export const meta: MetaFunction = () => { | ||
return [ | ||
{ | ||
title: "Veranstaltungen", | ||
}, | ||
{ | ||
name: "description", | ||
content: "Kommende Veranstaltungen vom LC Rehlingen" | ||
} | ||
] | ||
}; | ||
|
||
export async function loader() { | ||
const events = await getEvents({ | ||
results: false, | ||
}).then((res) => { | ||
return res.filter((event) => { | ||
return new Date(event.date) >= new Date(); | ||
}); | ||
}); | ||
return json({ | ||
events, | ||
}); | ||
} | ||
|
||
export default function EventListPage() { | ||
const { events } = useLoaderData<typeof loader>(); | ||
return ( | ||
<ContentContainer className="gap-4"> | ||
<Title name="Veranstaltungen" /> | ||
<ul className="grid grid-cols-1 gap-4 md:grid-cols-3"> | ||
{events.map((event, index: number) => ( | ||
<li key={index}> | ||
<EventCard | ||
event={{ | ||
date: event.date, | ||
name: event.name, | ||
slug: event.slug, | ||
}} | ||
image={{ | ||
height: 1080, | ||
width: 1920, | ||
src: "logo.png", | ||
}} | ||
/> | ||
</li> | ||
))} | ||
{ | ||
events.length === 0 && ( | ||
<li> | ||
<div className="font-medium flex-1 p-4"> | ||
Keine bevorstehenden Veranstaltungen | ||
</div> | ||
</li> | ||
) | ||
} | ||
</ul> | ||
</ContentContainer> | ||
); | ||
} |