diff --git a/package-lock.json b/package-lock.json index 38d051a2549c1c1e0b9d32c65d2d92abc104e3a3..5adc031cf4aac99277fa4c3d46c9979975107c5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,9 @@ "devDependencies": { "@sveltejs/kit": "^1.20.4", "@types/geojson": "^7946.0.11", + "@types/intl": "^1.2.0", "@types/leaflet": "^1.9.6", + "@types/node": "^20.8.0", "@typescript-eslint/eslint-plugin": "^6.7.3", "@typescript-eslint/parser": "^6.7.3", "autoprefixer": "^10.4.14", @@ -862,6 +864,12 @@ "integrity": "sha512-L7A0AINMXQpVwxHJ4jxD6/XjZ4NDufaRlUJHjNIFKYUFBH1SvOW+neaqb0VTRSLW5suSrSu19ObFEFnfNcr+qg==", "dev": true }, + "node_modules/@types/intl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/intl/-/intl-1.2.0.tgz", + "integrity": "sha512-BP+KwmOvD9AR5aoxnbyyPr3fAtpjEI/bVImHsotmpuC43+z0NAmjJ9cQbX7vPCq8XcvCeAVc8E3KSQPYNaPsUQ==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.13", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", @@ -877,6 +885,12 @@ "@types/geojson": "*" } }, + "node_modules/@types/node": { + "version": "20.8.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.0.tgz", + "integrity": "sha512-LzcWltT83s1bthcvjBmiBvGJiiUe84NWRHkw+ZV6Fr41z2FbIzvc815dk2nQ3RAKMuN2fkenM/z3Xv2QzEpYxQ==", + "devOptional": true + }, "node_modules/@types/pug": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.7.tgz", diff --git a/package.json b/package.json index fef107093afb72e411f94ab052abe1ec126ebc86..ca5e251dbabb6ef4fd603a04a323e4a93e445731 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,9 @@ "devDependencies": { "@sveltejs/kit": "^1.20.4", "@types/geojson": "^7946.0.11", + "@types/intl": "^1.2.0", "@types/leaflet": "^1.9.6", + "@types/node": "^20.8.0", "@typescript-eslint/eslint-plugin": "^6.7.3", "@typescript-eslint/parser": "^6.7.3", "autoprefixer": "^10.4.14", diff --git a/src/lib/components/MainLayout.svelte b/src/lib/components/MainLayout.svelte index 73e573f0fabf53394ee9a96a10829ceb49cccc13..c28a9d6d54d2d323cd976b73a176541390cd3757 100644 --- a/src/lib/components/MainLayout.svelte +++ b/src/lib/components/MainLayout.svelte @@ -1,11 +1,10 @@ <script> - import { DarkMode, Dropdown, DropdownItem, Footer, FooterCopyright, FooterLink, FooterLinkGroup, NavBrand, NavHamburger, NavLi, NavUl, Navbar } from 'flowbite-svelte'; + import { Button, DarkMode, Dropdown, DropdownItem, Footer, FooterCopyright, FooterLink, FooterLinkGroup, Modal, NavBrand, NavHamburger, NavLi, NavUl, Navbar, P } from 'flowbite-svelte'; import { Icon } from "flowbite-svelte-icons"; import { page } from '$app/stores'; import { browser } from '$app/environment'; - import { setLocale } from '$lib/i18n/i18n-svelte'; + import { setLocale, LL } from '$lib/i18n/i18n-svelte'; import { loadLocaleAsync } from '$lib/i18n/i18n-util.async'; - import LL from '$lib/i18n/i18n-svelte'; $: pathname = $page.url.pathname; @@ -21,6 +20,19 @@ })(); } + const firstPath = $page.url.pathname; + let showModal = false; + let unsubscribe = ()=>{}; + unsubscribe = firstPath !== "/rabatte" ? ()=>{} : page.subscribe(page=>{ + if(page.url.pathname !== "/rabatte"){ + unsubscribe(); + showModal = true; + } + }); + function acceptWarning(){ + showModal = false; + } + let showLanguageDropdown = false; </script> @@ -65,6 +77,12 @@ <slot /> </div> </div> + <Modal title={$LL.DiscountLeaveWarning.Title()} open={showModal} dismissable={false}> + <P>{$LL.DiscountLeaveWarning.Content()}</P> + <svelte:fragment slot="footer"> + <Button color="alternative" on:click={acceptWarning}>{$LL.DiscountLeaveWarning.Accept()}</Button> + </svelte:fragment> + </Modal> <Footer> <FooterCopyright by={$LL.Footer.Copyright()} copyrightMessage=""/> diff --git a/src/lib/i18n/de/index.ts b/src/lib/i18n/de/index.ts index 723072d67b53eb2db11b300054ea3cc150cf628e..1d446400e6b862feedf4af52725fc4e6ce85a952 100644 --- a/src/lib/i18n/de/index.ts +++ b/src/lib/i18n/de/index.ts @@ -173,9 +173,17 @@ const de = { NoResults: "Für deine aktuelle Suche existieren keine Angebote", // Anzeigetext, wenn kein Ergebnis der Suche entspricht }, }, + DiscountLeaveWarning: { // Warnung, wenn man von /rabatte woanders hin navigiert + Title: "Achtung Achtung!", + Content: "Die Seite zur Übersicht der Rabatte steht allen Fachschaften und somit allen Erstis zur Verfügung. Alle weiteren Seiten dieser Website sind nur für Erstis der Fachschaft Mathematik/Physik/Informatik (inklusive derer Lehramtserstis und WiMa-Erstis) gedacht. Solltest du dieser Fachschaft nicht zugehören, ist der restliche Inhalt für dich nicht relevant.", + Accept: "Zur Kenntnis genommen", // Knopf zum zur-Kenntnis-nehmen + }, ESWE: { Headline: "Erstsemesterwochenende", }, + Flyer: { + Notice: "Einige Flyer haben mehr als eine Seite. Wenn du auf das Bild klickst, kommst du zum vollständigen PDF.", + }, Legal: { // Text auf /impressum Headline: "Impressum", Address: "Adresse", diff --git a/src/lib/i18n/en/index.ts b/src/lib/i18n/en/index.ts index 6d85f7bc9432f069d41cd3d2fee3d410fead10d3..3732cf2e2fc716714b848313b9aa0fd847caf9f6 100644 --- a/src/lib/i18n/en/index.ts +++ b/src/lib/i18n/en/index.ts @@ -177,6 +177,9 @@ const en = { ESWE: { Headline: "Freshers' Weekend", }, + Flyer: { + Notice: "Some flyers have more than one page. You can get to the full PDF by clicking on the image.", + }, Legal: { // Text auf /impressum Headline: "Legal Notice", Address: "Address", diff --git a/src/lib/i18n/i18n-types.ts b/src/lib/i18n/i18n-types.ts index 0b7fc92efbd68a954d99b2f26a938376d50e2762..89e39566e5c41005810064b3d237a64f6f70745d 100644 --- a/src/lib/i18n/i18n-types.ts +++ b/src/lib/i18n/i18n-types.ts @@ -595,12 +595,32 @@ type RootTranslation = { NoResults: string } } + DiscountLeaveWarning: { + /** + * Achtung Achtung! + */ + Title: string + /** + * Die Seite zur Übersicht der Rabatte steht allen Fachschaften und somit allen Erstis zur Verfügung. Alle weiteren Seiten dieser Website sind nur für Erstis der Fachschaft Mathematik/Physik/Informatik (inklusive derer Lehramtserstis und WiMa-Erstis) gedacht. Solltest du dieser Fachschaft nicht zugehören, ist der restliche Inhalt für dich nicht relevant. + */ + Content: string + /** + * Zur Kenntnis genommen + */ + Accept: string + } ESWE: { /** * Erstsemesterwochenende */ Headline: string } + Flyer: { + /** + * Einige Flyer haben mehr als eine Seite. Wenn du auf das Bild klickst, kommst du zum vollständigen PDF. + */ + Notice: string + } Legal: { /** * Impressum @@ -1287,12 +1307,32 @@ export type TranslationFunctions = { NoResults: () => LocalizedString } } + DiscountLeaveWarning: { + /** + * Achtung Achtung! + */ + Title: () => LocalizedString + /** + * Die Seite zur Übersicht der Rabatte steht allen Fachschaften und somit allen Erstis zur Verfügung. Alle weiteren Seiten dieser Website sind nur für Erstis der Fachschaft Mathematik/Physik/Informatik (inklusive derer Lehramtserstis und WiMa-Erstis) gedacht. Solltest du dieser Fachschaft nicht zugehören, ist der restliche Inhalt für dich nicht relevant. + */ + Content: () => LocalizedString + /** + * Zur Kenntnis genommen + */ + Accept: () => LocalizedString + } ESWE: { /** * Erstsemesterwochenende */ Headline: () => LocalizedString } + Flyer: { + /** + * Einige Flyer haben mehr als eine Seite. Wenn du auf das Bild klickst, kommst du zum vollständigen PDF. + */ + Notice: () => LocalizedString + } Legal: { /** * Impressum diff --git a/src/lib/schedules.ts b/src/lib/schedules.ts index c7d805375eb0e264a16689aa5e3805b965254266..24705071bdc5bc1d3d7b5c1fd17cf1631938bd62 100644 --- a/src/lib/schedules.ts +++ b/src/lib/schedules.ts @@ -599,23 +599,25 @@ const scheduleLehramt: Schedule = { }, { title: "Facheinführung BiWi", + location: "H05", start: 10 * 60 + 0, end: 11 * 60 + 30, }, { - title: "Facheinführung Physik, Mathe und BiWi", + title: "Facheinführung Physik (H05), Mathe (Temp1) und BiWi (H05)", start: 13*60+0, end: 14*60+30, }, { - title: "Facheinführung Mathe und BiWi", + title: "Facheinführung Mathe (Temp1) und BiWi (H05)", start: 14*60+30, end: 16*60+0, }, { title: "Facheinführung Informatik", + location: "AH V", start: 16*60+0, - end: 18*60+0, + end: 17*60+30, }, { title: "Tutorienzeit", diff --git a/src/lib/server/db.js b/src/lib/server/db.js index 59d1ea56525214ce6d0bb7ae4b05659a2f2f404e..1f0d70cca9b88016c5a85480d06d0954ab7f901f 100644 --- a/src/lib/server/db.js +++ b/src/lib/server/db.js @@ -1,6 +1,6 @@ /* eslint-disable require-await */ import { config } from "./config"; -import discounts, { Tags } from "./discounts"; +import discounts, { Tags, holidays } from "./discounts"; /** * @typedef {Object} Tutor @@ -99,6 +99,10 @@ export async function getDiscountTags(){ return Tags; } +export async function getHolidays(){ + return [...holidays]; +} + export async function getStudyProgramsWithWaitlist(){ return [...config.waitlist]; } diff --git a/src/lib/server/discounts.ts b/src/lib/server/discounts.ts index 786eadb9550cee7aac48d80c234f7bd77da9e97f..cec5e7514fb893cbc89b063d59e0cd0ca6276b2f 100644 --- a/src/lib/server/discounts.ts +++ b/src/lib/server/discounts.ts @@ -13,6 +13,10 @@ export type Location = { end: string }; +export const holidays = [ + "2023-10-03", +]; + export type Tag = {[locale in Locales]: string}; export const Tags = { ASIAN: { @@ -180,7 +184,7 @@ export const discounts: Location[] = [ de: "10% auf alles", en: "10% off everything", }, - tags: [], + tags: [Tags.RESTAURANT, Tags.BOWLS], address: "Krämerstraße 7", location: [50.77576, 6.08444], open: { @@ -212,6 +216,7 @@ export const discounts: Location[] = [ 5: [[[11,30],[23,0]]], 6: [[[11,30],[23,0]]], 7: [], + holiday: [], }, start: "2023-10-02", end: "2023-10-06", @@ -275,6 +280,7 @@ export const discounts: Location[] = [ 5: [[[11,0],[23,0]]], 6: [[[11,0],[23,0]]], 7: [[[11,0],[23,0]]], + holiday: [[[11,0],[23,0]]], }, start: "2023-10-02", end: "2023-10-06", @@ -338,6 +344,7 @@ export const discounts: Location[] = [ 5: [[[12,0],[24,0]]], 6: [[[12,0],[24,0]]], 7: [[[12,0],[22,0]]], + holiday: [[[17,0],[23,0]]], }, start: "2023-10-02", end: "2023-10-13", @@ -590,6 +597,7 @@ export const discounts: Location[] = [ 5: [[[16,0],[24+1,0]]], 6: [[[16,0],[24+1,0]]], 7: [[[16,0],[24,0]]], + holiday: [], }, start: "2023-10-01", end: "2023-10-31", @@ -758,6 +766,7 @@ export const discounts: Location[] = [ 5: [[[16,30],[23,0]]], 6: [[[16,30],[23,0]]], 7: [[[11,30],[22,0]]], + holiday: [[[16,30],[22,30]]], }, start: "2023-10-02", end: "2023-10-06", @@ -804,6 +813,28 @@ export const discounts: Location[] = [ start: "2023-10-02", end: "2023-10-07", }, + { + name: "Café Stopover", + description: { + de: "20€ Gutschein für Erstis", + en: "20€ voucher for freshers", + }, + tags: [Tags.CAFE], + address: "Marienbongard 24-28", + location: [50.7802003, 6.0786301], + open: { + 1: [[[8,0],[18,0]]], + 2: [[[8,0],[18,0]]], + 3: [[[8,0],[18,0]]], + 4: [[[8,0],[17,0]]], + 5: [[[8,0],[17,0]]], + 6: [[[10,30],[16,30]]], + 7: [[[12,0],[17,0]]], + holiday: [[[12,0],[17,0]]], + }, + start: "2023-10-02", + end: "2023-12-15", + }, /* diff --git a/src/routes/(non-admin)/eswe/+page.svelte b/src/routes/(non-admin)/eswe/+page.svelte index 71f6f4bf45901b4da7fabd905921cc413d51a5f9..3c50d8e2740a51ecf3ad2b313f3f853d8dcd99a1 100644 --- a/src/routes/(non-admin)/eswe/+page.svelte +++ b/src/routes/(non-admin)/eswe/+page.svelte @@ -1,94 +1,102 @@ -<script lang="ts"> - import { A, Button, Carousel, Gallery, Heading, Li, List, Modal, P } from "flowbite-svelte"; - import LL from "$lib/i18n/i18n-svelte"; - - const images = [ - {src: "https://md.doetsch.page/uploads/0f5c2fa1-92a9-4c65-a4df-87fa7c63c6f4.JPG"}, - {src: "https://md.doetsch.page/uploads/22983672-610f-4460-b372-57f61ed97629.JPG"}, - {src: "https://md.doetsch.page/uploads/16777d3b-8e2b-4350-8a2a-404ae1e26301.JPG"}, - {src: "https://md.doetsch.page/uploads/9f08f05c-b6a0-4fa6-8049-976da3828376.JPG"}, - {src: "https://md.doetsch.page/uploads/c99c0398-9fe3-4f4b-855a-2612906bf0f6.JPG"}, - {src: "https://md.doetsch.page/uploads/44425363-690c-4974-8f27-0a8fcc96375e.JPG"}, - {src: "https://md.doetsch.page/uploads/cc9ad1ff-2ea8-4a1f-bd4d-09d8d042a3b3.JPG"}, - {src: "https://md.doetsch.page/uploads/0a8b0d3c-6b2d-4601-8ed8-145c0c689ef1.JPG"}, - {src: "https://md.doetsch.page/uploads/4ec6de7f-d575-40b9-a880-f30d394ba65d.JPG"}, - ]; - let showModal = false; - let index = 0; - function openModal(src: string){ - index = images.findIndex(i=>i.src===src); - showModal = true; - } - function handleKey(e: KeyboardEvent){ - if(e.key === "Escape") showModal = false; - else if(e.key === "ArrowLeft") index = (index-1+images.length)%images.length; - else if(e.key === "ArrowRight") index = (index+1)%images.length; - } -</script> - -<Heading tag="h1" customSize="text-4xl font-bold" class="mb-6 text-center">{$LL.ESWE.Headline()}</Heading> - -<P class="mb-3">Hallo liebe Erstis,</P> - -<P class="mb-3"> - auch dieses Jahr findet natürlich wieder das Erstsemesterwochenende (ESWE) statt! 🎊<br> - Wenn du vom <b>17.11. bis 19.11.</b> noch nichts zu tun hast und dann <b>volljährig</b> sein wirst, dann lies weiter und melde dich gerne unten an. -</P> - -<P class="mb-6">Deine ESA</P> - -<Heading tag="h2" customSize="text-3xl font-bold" class="mb-3 mt-6">Was ist das ESWE?</Heading> - -<P class="mb-6"> - Das ESWE ist ein jährliches Wochenende, an dem wir eine eigene Unterkunft mieten und dir damit die Möglichkeit bieten andere Erstis (und uns) besser kennen zu lernen.<br> - Wir haben hierbei immer freiwilliges lustiges Programm geplant und viele Spiele zur Unterhaltung dabei. -</P> - -<Heading tag="h2" customSize="text-3xl font-bold" class="mb-3 mt-6">Wieso sollte ich teilnehmen?</Heading> - -<List class="text-gray-900 dark:text-white"> - <Li>Du lernst viele neue Menschen kennen</Li> - <Li>Du hast ein Wochenende lang Spaß</Li> - <Li>Wir bekochen dich (manchmal musst du vielleicht helfen)</Li> - <Li>Alles inklusive, auch leckere Getränke (außer Alkohol)</Li> - <Li>Du hast ganz viel Spaß</Li> - <Li>Viel Spaß!</Li> -</List> - -<Heading tag="h2" customSize="text-3xl font-bold" class="mb-3 mt-6">ESWE dieses Jahr</Heading> - -<P class="mb-3"> - Das ESWE wird vom <b>17.11. bis 19.11.</b> im Landhaus Hohenfried in der Eifel stattfinden. Die Hin- und Rückfahrt werden wir mit den Öffis bewältigen.<br> - Dein Beitrag liegt bei <b>35€</b> und damit wird alles bis auf alkoholische Getränke inklusive sein. Bier wirst du vor Ort kaufen können und alles andere müsstest du selbst mitnehmen.<br> - Außerdem musst du am 17.11. <b>volljährig</b> sein. -</P> - -<P class="mb-6"> - Weitere Informationen wirst du nach der Anmeldung erfahren. Bei Fragen kannst du uns jederzeit eine <A href="mailto:esa@fsmpi.rwth-aachen.de">E-Mail</A> schreiben. -</P> - -<div class="flex mb-6 justify-center"> - <Button href="https://tickets.fsmpi.rwth-aachen.de/fsmpi/eswe2023/" target="_blank" size="xl">Zur Anmeldung</Button> -</div> - -<Heading tag="h2" customSize="text-3xl font-bold" class="mb-3 mt-6">Eindrücke aus 2022</Heading> - -<P class="mb-3">Voriges Jahr waren wir auch im Landhaus Hohenfried, hier ein paar Eindrücke:</P> - -<Gallery items={images} class="gap-4 grid-cols-2 md:grid-cols-3" let:item> - <div on:click={()=>openModal(item.src)} aria-haspopup="dialog" role="button" tabindex={0}> - <img src={item.src} alt="" class="h-auto max-w-full rounded-lg" /> - </div> -</Gallery> -<svelte:body on:keydown={handleKey} /> -<Modal bind:open={showModal} outsideclose dismissable={false} size="lg"> <!-- not dismissable bc missing z-index --> - <Carousel {images} let:Controls let:Indicators bind:index class="h-auto sm:h-auto xl:h-auto 2xl:h-auto"> - <Controls /> - <Indicators /> - <svelte:fragment slot="slide"> - {#key images[index].src} - <img src={images[index].src} alt="" /> - {/key} - </svelte:fragment> - </Carousel> -</Modal> +<script lang="ts"> + import { A, Button, Carousel, Gallery, Heading, Li, List, Modal, P } from "flowbite-svelte"; + import { LL, locale } from "$lib/i18n/i18n-svelte"; + + const images = [ + {src: "/eswe/0f5c2fa1-92a9-4c65-a4df-87fa7c63c6f4.JPG"}, + {src: "/eswe/22983672-610f-4460-b372-57f61ed97629.JPG"}, + {src: "/eswe/16777d3b-8e2b-4350-8a2a-404ae1e26301.JPG"}, + {src: "/eswe/9f08f05c-b6a0-4fa6-8049-976da3828376.JPG"}, + {src: "/eswe/c99c0398-9fe3-4f4b-855a-2612906bf0f6.JPG"}, + {src: "/eswe/44425363-690c-4974-8f27-0a8fcc96375e.JPG"}, + {src: "/eswe/cc9ad1ff-2ea8-4a1f-bd4d-09d8d042a3b3.JPG"}, + {src: "/eswe/0a8b0d3c-6b2d-4601-8ed8-145c0c689ef1.JPG"}, + {src: "/eswe/4ec6de7f-d575-40b9-a880-f30d394ba65d.JPG"}, + ]; + let showModal = false; + let index = 0; + function openModal(src: string){ + index = images.findIndex(i=>i.src===src); + showModal = true; + } + function handleKey(e: KeyboardEvent){ + if(e.key === "Escape") showModal = false; + else if(e.key === "ArrowLeft") index = (index-1+images.length)%images.length; + else if(e.key === "ArrowRight") index = (index+1)%images.length; + } +</script> + +<Heading tag="h1" customSize="text-4xl font-bold" class="mb-6 text-center">{$LL.ESWE.Headline()}</Heading> + +<svelte:body on:keydown={handleKey} /> +{#if $locale === "de"} +<P class="mb-3">Hallo liebe Erstis,</P> + +<P class="mb-3"> + auch dieses Jahr findet natürlich wieder das Erstsemesterwochenende (ESWE) statt! 🎊<br> + Wenn du vom <b>17.11. bis 19.11.</b> noch nichts zu tun hast und dann <b>volljährig</b> sein wirst, dann lies weiter und melde dich gerne unten an. +</P> + +<P class="mb-6">Deine ESA</P> + +<Heading tag="h2" customSize="text-3xl font-bold" class="mb-3 mt-6">Was ist das ESWE?</Heading> + +<P class="mb-6"> + Das ESWE ist ein jährliches Wochenende, an dem wir eine eigene Unterkunft mieten und dir damit die Möglichkeit bieten andere Erstis (und uns) besser kennen zu lernen.<br> + Wir haben hierbei immer freiwilliges lustiges Programm geplant und viele Spiele zur Unterhaltung dabei. +</P> + +<Heading tag="h2" customSize="text-3xl font-bold" class="mb-3 mt-6">Wieso sollte ich teilnehmen?</Heading> + +<List class="text-gray-900 dark:text-white"> + <Li>Du lernst viele neue Menschen kennen</Li> + <Li>Du hast ein Wochenende lang Spaß</Li> + <Li>Wir bekochen dich (manchmal musst du vielleicht helfen)</Li> + <Li>Alles inklusive, auch leckere Getränke (außer Alkohol)</Li> + <Li>Du hast ganz viel Spaß</Li> + <Li>Viel Spaß!</Li> +</List> + +<Heading tag="h2" customSize="text-3xl font-bold" class="mb-3 mt-6">ESWE dieses Jahr</Heading> + +<P class="mb-3"> + Das ESWE wird vom <b>17.11. bis 19.11.</b> im Landhaus Hohenfried in der Eifel stattfinden. Die Hin- und Rückfahrt werden wir mit den Öffis bewältigen.<br> + Dein Beitrag liegt bei <b>35€</b> und damit wird alles bis auf alkoholische Getränke inklusive sein. Bier wirst du vor Ort kaufen können und alles andere müsstest du selbst mitnehmen.<br> + Außerdem musst du am 17.11. <b>volljährig</b> sein. +</P> + +<P class="mb-6"> + Weitere Informationen wirst du nach der Anmeldung erfahren. Bei Fragen kannst du uns jederzeit eine <A href="mailto:esa@fsmpi.rwth-aachen.de">E-Mail</A> schreiben. +</P> + +<div class="flex mb-6 justify-center"> + {#if Date.now() < new Date("2023-10-02T06:00:00+0200").getTime()} + <Button disabled size="xl">Die Anmeldung öffnet bald</Button> + {:else} + <Button href="https://tickets.fsmpi.rwth-aachen.de/fsmpi/eswe2023/" target="_blank" size="xl">Zur Anmeldung</Button> + {/if} +</div> + +<Heading tag="h2" customSize="text-3xl font-bold" class="mb-3 mt-6">Eindrücke aus 2022</Heading> + +<P class="mb-3">Voriges Jahr waren wir auch im Landhaus Hohenfried, hier ein paar Eindrücke:</P> + +<Gallery items={images} class="gap-4 grid-cols-2 md:grid-cols-3" let:item> + <div on:click={()=>openModal(item.src)} aria-haspopup="dialog" role="button" tabindex={0} on:keydown={e=>e.key==="Enter"&&openModal(item.src)}> + <img src={item.src} alt="" class="h-auto max-w-full rounded-lg" /> + </div> +</Gallery> +<Modal bind:open={showModal} outsideclose dismissable={false} size="lg"> <!-- not dismissable bc missing z-index --> + <Carousel {images} let:Controls let:Indicators bind:index class="h-auto sm:h-auto xl:h-auto 2xl:h-auto"> + <Controls /> + <Indicators /> + <svelte:fragment slot="slide"> + {#key images[index].src} + <img src={images[index].src} alt="" /> + {/key} + </svelte:fragment> + </Carousel> +</Modal> +{:else} +<P>The Freshers' Weekend is an event for bachelor freshers only that will be held completely in German. For more information look at the German version.</P> +{/if} diff --git a/src/routes/(non-admin)/flyer/+page.svelte b/src/routes/(non-admin)/flyer/+page.svelte index 247578cfbf2058862d0829eaab6bdd24c7132e06..7d7cd91b8b22ed0374372cf02859784126747c87 100644 --- a/src/routes/(non-admin)/flyer/+page.svelte +++ b/src/routes/(non-admin)/flyer/+page.svelte @@ -2,6 +2,7 @@ import { Carousel, Thumbnails } from 'flowbite-svelte'; import { quintOut } from 'svelte/easing'; import { fade } from 'svelte/transition'; + import LL from '$lib/i18n/i18n-svelte'; /** @type {import('./$types').PageData} */ export let data; @@ -16,15 +17,14 @@ <a slot="slide" href="/flyer/{data.flyer[index]}.pdf" target="_blank" let:Slide> <!--<Slide image={images[index]} class="object-contain w-full h-full" />--> {#key data.flyer[index]} - <img src={"/flyer/" + data.flyer[index] + "_hq.jpg"} alt={data.flyer[index]} class="absolute block w-full h-full object-contain" transition:slideTransition={{}} /> + <img src={"/flyer/" + data.flyer[index] + "_hq.jpg"} alt={data.flyer[index]} class="absolute block w-full h-full object-contain" transition:slideTransition /> {/key} </a> </Carousel> - <Thumbnails images={data.flyer.map(flyer=>({src: "/flyer/" + flyer+"_lq.jpg", alt: flyer}))} bind:index class="h-20 dark:bg-gray-800" let:Thumbnail let:image let:selected> - <Thumbnail {...image} {selected} class="h-20" /> + <Thumbnails images={data.flyer.map(flyer=>({src: "/flyer/" + flyer+"_lq.jpg", alt: flyer}))} bind:index class="max-h-20 h-auto dark:bg-gray-800" let:Thumbnail let:image let:selected> + <Thumbnail {...image} {selected} class="max-h-20 h-auto" /> </Thumbnails> <div class="rounded bg-gray-300 dark:bg-gray-700 dark:text-white p-2 my-2 text-center"> - <!-- TODO i18n --> - {"Einige Flyer haben mehr als eine Seite. Wenn du auf das Bild klickst, kommst du zum vollständigen PDF."} + {$LL.Flyer.Notice()} </div> </div> diff --git a/src/routes/(non-admin)/rabatte/+page.server.ts b/src/routes/(non-admin)/rabatte/+page.server.ts index 293fe7c10782e4216e23977ca884881fa6d999c5..3a6654307dc01da0152d2e986eeccffa33f5d190 100644 --- a/src/routes/(non-admin)/rabatte/+page.server.ts +++ b/src/routes/(non-admin)/rabatte/+page.server.ts @@ -1,9 +1,10 @@ -import { getDiscountTags, getDiscounts } from "$lib/server/db.js"; +import { getDiscountTags, getDiscounts, getHolidays } from "$lib/server/db.js"; import type { PageServerLoad } from "./$types"; export const load: PageServerLoad = async () => { return { locations: await getDiscounts(), allTags: Object.values(await getDiscountTags()), + holidays: await getHolidays(), }; }; diff --git a/src/routes/(non-admin)/rabatte/+page.svelte b/src/routes/(non-admin)/rabatte/+page.svelte index 3f7d588b52207a7411130b263aaa2fa2e46fd48a..7392c227fe98c73e23fc3dee30710f4dbde962c9 100644 --- a/src/routes/(non-admin)/rabatte/+page.svelte +++ b/src/routes/(non-admin)/rabatte/+page.svelte @@ -30,7 +30,7 @@ const locations = data.locations .map((location, i) => Object.assign( location, - isOpen(location.open, new Date()), + isOpen(data.holidays, location.open, new Date()), {id: i}, {status: getValidityStatus(location.start, location.end, Date.now())}, )) @@ -212,9 +212,9 @@ </style> <div class="map-container z-40 mx-auto max-w-6xl px-4" bind:this={mapContainer}> - <LeafletMap {locations} {scrollTo} bind:showOnMap /> + <LeafletMap {locations} {scrollTo} bind:showOnMap holidays={data.holidays} /> </div> <div class="list-container"> <LocationFilter {allTags} bind:onlyOpen bind:search bind:tags /> - <LocationList {locations} filter={filter(search, tags, onlyOpen)} showOnMap={focusLocationOnMap} bind:locationElements bind:searchTags={tags} /> + <LocationList {locations} holidays={data.holidays} filter={filter(search, tags, onlyOpen)} showOnMap={focusLocationOnMap} bind:locationElements bind:searchTags={tags} /> </div> diff --git a/src/routes/(non-admin)/rabatte/assets/LeafletMap.svelte b/src/routes/(non-admin)/rabatte/assets/LeafletMap.svelte index 94addaa95e5c83f735fe80b21eaebe8103be84fc..6a6cf4baef2e70b70d8d849a054ef926319ced8d 100644 --- a/src/routes/(non-admin)/rabatte/assets/LeafletMap.svelte +++ b/src/routes/(non-admin)/rabatte/assets/LeafletMap.svelte @@ -8,7 +8,10 @@ import type { Map, Marker } from 'leaflet'; let leaflet: typeof import("leaflet"); - export let locations: (Location&{id: number, closingSoon: boolean, openingSoon: boolean, isOpen: boolean})[], scrollTo: (id: number)=>void; + export let + locations: (Location&{id: number, closingSoon: boolean, openingSoon: boolean, isOpen: boolean})[], + scrollTo: (id: number)=>void, + holidays: string[]; let map: Map; let mapElement: HTMLDivElement; @@ -58,7 +61,7 @@ // add markers const unsubscribers: Unsubscriber[] = []; locations.forEach(location=>{ - const openingHours = getOpeningHoursForNextDays(location.open, new Date(), 3, true); + const openingHours = getOpeningHoursForNextDays(holidays, location.open, new Date(), 3, true); const tableDiv = document.createElement("div"); tableDiv.appendChild(formatOpeningHoursAsTable(openingHours, $locale)); const popup = document.createElement("div"); diff --git a/src/routes/(non-admin)/rabatte/assets/Location.svelte b/src/routes/(non-admin)/rabatte/assets/Location.svelte index f90242736c891e6c17fc979869ea215366bc6d22..f4dcd3516bf06389bdb15c3cb4b392312c39fe46 100644 --- a/src/routes/(non-admin)/rabatte/assets/Location.svelte +++ b/src/routes/(non-admin)/rabatte/assets/Location.svelte @@ -11,12 +11,13 @@ location: LocationType&{status:number,closingSoon:boolean,isOpen:boolean,openingSoon:boolean}, showOnMap: MouseEventHandler<HTMLAnchorElement>, searchTags: Tag[], - locationElement: HTMLElement; + locationElement: HTMLElement, + holidays: string[]; let element: HTMLDivElement; $: locationElement = element?.parentElement as HTMLElement; - $: open = formatOpeningHours(getOpeningHoursForNextDays(location.open, new Date(), 7, true), $locale); + $: open = formatOpeningHours(getOpeningHoursForNextDays(holidays, location.open, new Date(), 7, true), $locale); let showAllOpeningHours = false; $: rangeFormatter = new Intl.DateTimeFormat($locale, {day: "2-digit", month: "long"}); diff --git a/src/routes/(non-admin)/rabatte/assets/LocationList.svelte b/src/routes/(non-admin)/rabatte/assets/LocationList.svelte index bdc88d3e83eeb8d3f9a5f5345a12bb0e02a17cbd..63a869b7635da7e8cdbaac87566f95f2b3eb5629 100644 --- a/src/routes/(non-admin)/rabatte/assets/LocationList.svelte +++ b/src/routes/(non-admin)/rabatte/assets/LocationList.svelte @@ -4,7 +4,11 @@ import { P } from 'flowbite-svelte'; import type { Location as LocationType, Tag } from '$lib/server/discounts'; - export let locations: (LocationType&{id:number})[], filter: (location: LocationType)=>boolean, showOnMap: (id: number)=>void, searchTags: Tag[]; + export let + locations: (LocationType&{id:number})[], filter: (location: LocationType)=>boolean, + showOnMap: (id: number)=>void, + searchTags: Tag[], + holidays: string[]; export const locationElements: {[k: number]: HTMLDivElement} = {}; $: filteredLocations = locations.filter(filter); </script> @@ -17,7 +21,7 @@ <div class="grid gap-4 mb-5"> {#each filteredLocations as location (location.id)} - <Location {location} bind:searchTags showOnMap={()=>showOnMap(location.id)} bind:locationElement={locationElements[location.id]} /> + <Location {location} {holidays} bind:searchTags showOnMap={()=>showOnMap(location.id)} bind:locationElement={locationElements[location.id]} /> {/each} {#if filteredLocations.length === 0} <P>{$LL.Discounts.Search.NoResults()}</P> diff --git a/src/routes/(non-admin)/rabatte/assets/opening.ts b/src/routes/(non-admin)/rabatte/assets/opening.ts index f43cc55573a020fe8b2608150856bab3bcb39929..44e8fb8d4fde1665c718bd1840bff5d21067f2ce 100644 --- a/src/routes/(non-admin)/rabatte/assets/opening.ts +++ b/src/routes/(non-admin)/rabatte/assets/opening.ts @@ -14,24 +14,24 @@ function formatDate(date: Date): string { return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`; } -export function getOpeningHoursForWeek(open: GeneralOpeningHours, date: Date): [OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay] { +export function getOpeningHoursForWeek(holidays: string[], open: GeneralOpeningHours, date: Date): [OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay] { const day = date.getDay() || 7; date.setDate(date.getDate() - day + 1); // Monday of same week - return getOpeningHoursForNextDays(open, date, 7) as [OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay]; + return getOpeningHoursForNextDays(holidays, open, date, 7) as [OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay, OpeningHoursForDay]; } -export function getOpeningHoursForNextDays(open: GeneralOpeningHours, date: Date, days = 7, startYesterdayIfOpen = false): OpeningHoursForDay[] { +export function getOpeningHoursForNextDays(holidays: string[], open: GeneralOpeningHours, date: Date, days = 7, startYesterdayIfOpen = false): OpeningHoursForDay[] { const openingTimes: OpeningHoursForDay[] = []; if(startYesterdayIfOpen){ const yesterday = new Date(date.getTime() - 86400000); - const fromYesterday = getOpeningHoursForDay(open, yesterday); + const fromYesterday = getOpeningHoursForDay(holidays, open, yesterday); if(fromYesterday.openingHours.some(([, [eh, em]]) => (eh > 24 || (eh === 24 && em > 0)) && date.getTime() < new Date(yesterday).setHours(eh, em))) { days--; openingTimes.push(fromYesterday); } } for(let i = 0; i < days; i++){ - openingTimes.push(getOpeningHoursForDay(open, date)); + openingTimes.push(getOpeningHoursForDay(holidays, open, date)); date.setDate(date.getDate() + 1); } return openingTimes; @@ -43,7 +43,7 @@ export function getOpeningHoursForNextDays(open: GeneralOpeningHours, date: Date * @param includeYesterday Whether a [[x,y],[25,0]] from the previous day should be included as [[x-24,y],[1,0]]. Should be true for calculating, should be false for displaying. * @returns */ -export function getOpeningHoursForDay(open: GeneralOpeningHours, date: Date, includeYesterday = false): OpeningHoursForDay { +export function getOpeningHoursForDay(holidays: string[], open: GeneralOpeningHours, date: Date, includeYesterday = false): OpeningHoursForDay { const day = date.getDay() || 7; const dateString = formatDate(date).slice(0, 10); let fromYesterday: OpeningHours = []; @@ -60,6 +60,12 @@ export function getOpeningHoursForDay(open: GeneralOpeningHours, date: Date, inc openingHours: fromYesterday.concat(open[dateString]), different: true, }; + }else if(open.holiday && holidays.includes(dateString) && open[day]?.length !== 0){ // wenn am Tag generell geschlossen, dann hat das Vorrang gegenüber Feiertag + return { + date: dateString, + openingHours: fromYesterday.concat(open.holiday), + different: true, + }; }else{ return { date: dateString, @@ -120,7 +126,7 @@ export function formatOpeningHoursAsTable(open: OpeningHoursForDay[], locale: Lo return table; } -export function isOpen(openingHours: GeneralOpeningHours, now: Date, minutes = 30){ +export function isOpen(holidays: string[], openingHours: GeneralOpeningHours, now: Date, minutes = 30){ now.setSeconds(0, 0); const year = now.getFullYear(); const month = now.getMonth(); @@ -128,7 +134,7 @@ export function isOpen(openingHours: GeneralOpeningHours, now: Date, minutes = 3 const hour = now.getHours(); const minute = now.getMinutes(); const soon = new Date(year, month, day, hour, minute + minutes); - const openingHoursForDay = getOpeningHoursForDay(openingHours, now, true); + const openingHoursForDay = getOpeningHoursForDay(holidays, openingHours, now, true); let isOpen = false; let openingSoon = false; let closingSoon = false; diff --git a/static/eswe/0a8b0d3c-6b2d-4601-8ed8-145c0c689ef1.JPG b/static/eswe/0a8b0d3c-6b2d-4601-8ed8-145c0c689ef1.JPG new file mode 100644 index 0000000000000000000000000000000000000000..84c0d79b2da8f6b52c3ef14669135ae53fe83b71 Binary files /dev/null and b/static/eswe/0a8b0d3c-6b2d-4601-8ed8-145c0c689ef1.JPG differ diff --git a/static/eswe/0f5c2fa1-92a9-4c65-a4df-87fa7c63c6f4.JPG b/static/eswe/0f5c2fa1-92a9-4c65-a4df-87fa7c63c6f4.JPG new file mode 100644 index 0000000000000000000000000000000000000000..acca65237a18aa67dfb02c86dcc17154d4cff1a0 Binary files /dev/null and b/static/eswe/0f5c2fa1-92a9-4c65-a4df-87fa7c63c6f4.JPG differ diff --git a/static/eswe/16777d3b-8e2b-4350-8a2a-404ae1e26301.JPG b/static/eswe/16777d3b-8e2b-4350-8a2a-404ae1e26301.JPG new file mode 100644 index 0000000000000000000000000000000000000000..5392b1b90aa94c9deb21da31b6fce7c2defa07aa Binary files /dev/null and b/static/eswe/16777d3b-8e2b-4350-8a2a-404ae1e26301.JPG differ diff --git a/static/eswe/22983672-610f-4460-b372-57f61ed97629.JPG b/static/eswe/22983672-610f-4460-b372-57f61ed97629.JPG new file mode 100644 index 0000000000000000000000000000000000000000..5059825ec659864fde8c7206f8491ee308dd4d25 Binary files /dev/null and b/static/eswe/22983672-610f-4460-b372-57f61ed97629.JPG differ diff --git a/static/eswe/44425363-690c-4974-8f27-0a8fcc96375e.JPG b/static/eswe/44425363-690c-4974-8f27-0a8fcc96375e.JPG new file mode 100644 index 0000000000000000000000000000000000000000..6ec308716367271636b2b0eae0552a7c77681ba0 Binary files /dev/null and b/static/eswe/44425363-690c-4974-8f27-0a8fcc96375e.JPG differ diff --git a/static/eswe/4ec6de7f-d575-40b9-a880-f30d394ba65d.JPG b/static/eswe/4ec6de7f-d575-40b9-a880-f30d394ba65d.JPG new file mode 100644 index 0000000000000000000000000000000000000000..0a21c5a962bc7aea78e26818e25026c623d4b51a Binary files /dev/null and b/static/eswe/4ec6de7f-d575-40b9-a880-f30d394ba65d.JPG differ diff --git a/static/eswe/9f08f05c-b6a0-4fa6-8049-976da3828376.JPG b/static/eswe/9f08f05c-b6a0-4fa6-8049-976da3828376.JPG new file mode 100644 index 0000000000000000000000000000000000000000..453ac4d0d407c20eb313ea0b213d816b17c711a4 Binary files /dev/null and b/static/eswe/9f08f05c-b6a0-4fa6-8049-976da3828376.JPG differ diff --git a/static/eswe/c99c0398-9fe3-4f4b-855a-2612906bf0f6.JPG b/static/eswe/c99c0398-9fe3-4f4b-855a-2612906bf0f6.JPG new file mode 100644 index 0000000000000000000000000000000000000000..c65146002760d950cb4923229c84291a36bc15e5 Binary files /dev/null and b/static/eswe/c99c0398-9fe3-4f4b-855a-2612906bf0f6.JPG differ diff --git a/static/eswe/cc9ad1ff-2ea8-4a1f-bd4d-09d8d042a3b3.JPG b/static/eswe/cc9ad1ff-2ea8-4a1f-bd4d-09d8d042a3b3.JPG new file mode 100644 index 0000000000000000000000000000000000000000..61946cf61a5de63dfb63dd8aecfdf16884738e95 Binary files /dev/null and b/static/eswe/cc9ad1ff-2ea8-4a1f-bd4d-09d8d042a3b3.JPG differ diff --git a/static/flyer/Semesterbroschuere_Zentrale_Studienberatung.pdf b/static/flyer/Semesterbroschuere_Zentrale_Studienberatung.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9175e344fa6f23920679d6f5f9babd3bbb66679b Binary files /dev/null and b/static/flyer/Semesterbroschuere_Zentrale_Studienberatung.pdf differ diff --git a/static/flyer/jDPG-Schlag-den-Prof.pdf b/static/flyer/jDPG-Schlag-den-Prof.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6a8eeb8d9f834478927577b560a436d24c10ea97 Binary files /dev/null and b/static/flyer/jDPG-Schlag-den-Prof.pdf differ diff --git a/static/stundenplaene/stundenplan-lehramt-dark.png b/static/stundenplaene/stundenplan-lehramt-dark.png index de9881b344bb115cd59044c3d234c6f8c310b0cb..527291f6b845c89d6269c899494d6ccf24072ecc 100644 Binary files a/static/stundenplaene/stundenplan-lehramt-dark.png and b/static/stundenplaene/stundenplan-lehramt-dark.png differ diff --git a/static/stundenplaene/stundenplan-lehramt.pdf b/static/stundenplaene/stundenplan-lehramt.pdf index a4640afef1db533e13b1a071359d05db1daf98ee..1dc2e9c5943188445545d8a5d829b82d1fae4207 100644 Binary files a/static/stundenplaene/stundenplan-lehramt.pdf and b/static/stundenplaene/stundenplan-lehramt.pdf differ diff --git a/static/stundenplaene/stundenplan-lehramt.png b/static/stundenplaene/stundenplan-lehramt.png index feb88564c9b643ebb3dd061d1e00d2003ccd6296..0a4a919f8ebd1f9d3d973c31bdf85a7bfa089665 100644 Binary files a/static/stundenplaene/stundenplan-lehramt.png and b/static/stundenplaene/stundenplan-lehramt.png differ