mirror of
https://github.com/skidoodle/erettsegi-browser.git
synced 2026-04-28 13:37:35 +02:00
update
This commit is contained in:
+60
-60
@@ -1,73 +1,73 @@
|
||||
import { Button } from '@nextui-org/react'
|
||||
import React, { useState, useEffect, useCallback } from 'react'
|
||||
import type { ButtonProps } from '@/utils/props'
|
||||
import type { ButtonColor } from '@/utils/types'
|
||||
import { Button } from "@heroui/react";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import type { ButtonProps } from "@/utils/props";
|
||||
import type { ButtonColor } from "@/utils/types";
|
||||
|
||||
const CustomButton: React.FC<ButtonProps> = React.memo(({ label, link }) => {
|
||||
const [status, setStatus] = useState<number>()
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false)
|
||||
const [status, setStatus] = useState<number>();
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
const checkLinkStatus = useCallback(async (): Promise<void> => {
|
||||
if (link) {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
const response = await fetch(`/api/validate?link=${encodeURI(link)}`)
|
||||
const data = (await response.json()) as { status: number }
|
||||
setStatus(data.status)
|
||||
} catch (error) {
|
||||
setStatus(500)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
}, [link])
|
||||
const checkLinkStatus = useCallback(async (): Promise<void> => {
|
||||
if (link) {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await fetch(`/api/validate?link=${encodeURI(link)}`);
|
||||
const data = (await response.json()) as { status: number };
|
||||
setStatus(data.status);
|
||||
} catch (_error) {
|
||||
setStatus(500);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
}, [link]);
|
||||
|
||||
useEffect(() => {
|
||||
void checkLinkStatus()
|
||||
}, [checkLinkStatus])
|
||||
useEffect(() => {
|
||||
void checkLinkStatus();
|
||||
}, [checkLinkStatus]);
|
||||
|
||||
const getColor = useCallback((): ButtonColor => {
|
||||
switch (true) {
|
||||
case isLoading:
|
||||
return 'default'
|
||||
case status === 200:
|
||||
return 'primary'
|
||||
case status === 404:
|
||||
return 'danger'
|
||||
default:
|
||||
return 'default'
|
||||
}
|
||||
}, [isLoading, status])
|
||||
const getColor = useCallback((): ButtonColor => {
|
||||
switch (true) {
|
||||
case isLoading:
|
||||
return "default";
|
||||
case status === 200:
|
||||
return "primary";
|
||||
case status === 404:
|
||||
return "danger";
|
||||
default:
|
||||
return "default";
|
||||
}
|
||||
}, [isLoading, status]);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (status === 200 && link) {
|
||||
window.open(link)
|
||||
} else {
|
||||
console.error('A hivatkozás nem elérhető.')
|
||||
}
|
||||
}, [status, link])
|
||||
const handleClick = useCallback(() => {
|
||||
if (status === 200 && link) {
|
||||
window.open(link);
|
||||
} else {
|
||||
console.error("A hivatkozás nem elérhető.");
|
||||
}
|
||||
}, [status, link]);
|
||||
|
||||
return (
|
||||
<Button
|
||||
isDisabled={status !== 200 || !link || isLoading}
|
||||
isLoading={isLoading}
|
||||
className='w-28 mt-3 text-sm font-bold py-2 px-2'
|
||||
color={getColor()}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
)
|
||||
})
|
||||
return (
|
||||
<Button
|
||||
isDisabled={status !== 200 || !link || isLoading}
|
||||
isLoading={isLoading}
|
||||
className="w-28 mt-3 text-sm font-bold py-2 px-2"
|
||||
color={getColor()}
|
||||
onPress={handleClick}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
});
|
||||
|
||||
export const PdfButton: React.FC<ButtonProps> = React.memo(
|
||||
({ label, link }) => <CustomButton label={label} link={link} />
|
||||
)
|
||||
({ label, link }) => <CustomButton label={label} link={link} />,
|
||||
);
|
||||
|
||||
export const ZipButton: React.FC<ButtonProps> = React.memo(
|
||||
({ label, link }) => <CustomButton label={label} link={link} />
|
||||
)
|
||||
({ label, link }) => <CustomButton label={label} link={link} />,
|
||||
);
|
||||
|
||||
export const Mp3Button: React.FC<ButtonProps> = React.memo(
|
||||
({ label, link }) => <CustomButton label={label} link={link} />
|
||||
)
|
||||
({ label, link }) => <CustomButton label={label} link={link} />,
|
||||
);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { ThemeSwitcher } from '@/components/ThemeSwitcher'
|
||||
import { Source } from '@/components/Source'
|
||||
import { Source } from "@/components/Source";
|
||||
import { ThemeSwitcher } from "@/components/ThemeSwitcher";
|
||||
|
||||
export const Footer = () => {
|
||||
return (
|
||||
<div className='fixed bottom-0 py-5 left-0 right-0 text-center space-x-5'>
|
||||
<Source />
|
||||
<ThemeSwitcher />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className="fixed bottom-0 py-5 left-0 right-0 text-center space-x-5">
|
||||
<Source />
|
||||
<ThemeSwitcher />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,80 +1,77 @@
|
||||
import { Select, SelectItem } from '@nextui-org/react'
|
||||
import type { SelectorProps } from '@/utils/props'
|
||||
import { Select, SelectItem } from "@heroui/react";
|
||||
import type { SelectorProps } from "@/utils/props";
|
||||
import type { ChangeEvent } from "react";
|
||||
|
||||
export const SubjectSelector: React.FC<
|
||||
Pick<SelectorProps, 'selectedSubject' | 'setSelectedSubject' | 'subjects'>
|
||||
Pick<SelectorProps, "selectedSubject" | "setSelectedSubject" | "subjects">
|
||||
> = ({ selectedSubject, setSelectedSubject, subjects }) => (
|
||||
<Select
|
||||
selectionMode='single'
|
||||
disallowEmptySelection={true}
|
||||
label='Tárgy'
|
||||
value={selectedSubject}
|
||||
onChange={(e) => setSelectedSubject(e.target.value)}
|
||||
className='w-56'
|
||||
>
|
||||
{subjects.map((subject) => (
|
||||
<SelectItem key={subject.value} value={subject.value}>
|
||||
{subject.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
)
|
||||
<Select
|
||||
selectionMode="single"
|
||||
disallowEmptySelection={true}
|
||||
label="Tárgy"
|
||||
value={selectedSubject}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) =>
|
||||
setSelectedSubject(e.target.value)
|
||||
}
|
||||
className="w-56"
|
||||
>
|
||||
{subjects.map((subject) => (
|
||||
<SelectItem key={subject.value}>{subject.label}</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
|
||||
export const YearSelector: React.FC<
|
||||
Pick<SelectorProps, 'selectedYear' | 'setSelectedYear' | 'years'>
|
||||
Pick<SelectorProps, "selectedYear" | "setSelectedYear" | "years">
|
||||
> = ({ selectedYear, setSelectedYear, years }) => (
|
||||
<Select
|
||||
selectionMode='single'
|
||||
disallowEmptySelection={true}
|
||||
label='Év'
|
||||
value={selectedYear}
|
||||
onChange={(e) => setSelectedYear(e.target.value)}
|
||||
className='w-56'
|
||||
>
|
||||
{years.map((year) => (
|
||||
<SelectItem key={year} value={year}>
|
||||
{year}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
)
|
||||
<Select
|
||||
selectionMode="single"
|
||||
disallowEmptySelection={true}
|
||||
label="Év"
|
||||
value={selectedYear}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) =>
|
||||
setSelectedYear(e.target.value)
|
||||
}
|
||||
className="w-56"
|
||||
>
|
||||
{years.map((year) => (
|
||||
<SelectItem key={year}>{year}</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
|
||||
export const PeriodSelector: React.FC<
|
||||
Pick<SelectorProps, 'selectedPeriod' | 'setSelectedPeriod'>
|
||||
Pick<SelectorProps, "selectedPeriod" | "setSelectedPeriod">
|
||||
> = ({ selectedPeriod, setSelectedPeriod }) => (
|
||||
<Select
|
||||
selectionMode='single'
|
||||
disallowEmptySelection={true}
|
||||
label='Időszak'
|
||||
value={selectedPeriod}
|
||||
onChange={(e) => setSelectedPeriod(e.target.value)}
|
||||
className='w-56'
|
||||
>
|
||||
<SelectItem key={'tavasz'} value={'tavasz'}>
|
||||
Tavasz
|
||||
</SelectItem>
|
||||
<SelectItem key={'osz'} value={'osz'}>
|
||||
Ősz
|
||||
</SelectItem>
|
||||
</Select>
|
||||
)
|
||||
<Select
|
||||
selectionMode="single"
|
||||
disallowEmptySelection={true}
|
||||
label="Időszak"
|
||||
value={selectedPeriod}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) =>
|
||||
setSelectedPeriod(e.target.value)
|
||||
}
|
||||
className="w-56"
|
||||
>
|
||||
<SelectItem key={"tavasz"}>Tavasz</SelectItem>
|
||||
<SelectItem key={"osz"}>Ősz</SelectItem>
|
||||
</Select>
|
||||
);
|
||||
|
||||
export const LevelSelector: React.FC<
|
||||
Pick<SelectorProps, 'selectedLevel' | 'setSelectedLevel'>
|
||||
Pick<SelectorProps, "selectedLevel" | "setSelectedLevel">
|
||||
> = ({ selectedLevel, setSelectedLevel }) => (
|
||||
<Select
|
||||
selectionMode='single'
|
||||
disallowEmptySelection={true}
|
||||
label='Szint'
|
||||
value={selectedLevel}
|
||||
onChange={(e) => setSelectedLevel(e.target.value)}
|
||||
className='w-56'
|
||||
>
|
||||
<SelectItem key={'kozep'} value={'kozep'}>
|
||||
Közép
|
||||
</SelectItem>
|
||||
<SelectItem key={'emelt'} value={'emelt'}>
|
||||
Emelt
|
||||
</SelectItem>
|
||||
</Select>
|
||||
)
|
||||
<Select
|
||||
selectionMode="single"
|
||||
disallowEmptySelection={true}
|
||||
label="Szint"
|
||||
value={selectedLevel}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) =>
|
||||
setSelectedLevel(e.target.value)
|
||||
}
|
||||
className="w-56"
|
||||
>
|
||||
<SelectItem key={"kozep"}>Közép</SelectItem>
|
||||
<SelectItem key={"emelt"}>Emelt</SelectItem>
|
||||
</Select>
|
||||
);
|
||||
|
||||
+14
-14
@@ -1,16 +1,16 @@
|
||||
import { VscGithubInverted } from 'react-icons/vsc'
|
||||
import { Button } from '@nextui-org/button'
|
||||
import { Button } from "@heroui/button";
|
||||
import { VscGithubInverted } from "react-icons/vsc";
|
||||
|
||||
export const Source = () => {
|
||||
return (
|
||||
<Button
|
||||
aria-label='Source Code'
|
||||
size='sm'
|
||||
onClick={() =>
|
||||
window.open('https://github.com/skidoodle/erettsegi-browser')
|
||||
}
|
||||
>
|
||||
<VscGithubInverted size={20} />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Button
|
||||
aria-label="Source Code"
|
||||
size="sm"
|
||||
onPress={() =>
|
||||
window.open("https://github.com/skidoodle/erettsegi-browser")
|
||||
}
|
||||
>
|
||||
<VscGithubInverted size={20} />
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import { VscColorMode } from 'react-icons/vsc'
|
||||
import { Button } from '@nextui-org/button'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { Button } from "@heroui/button";
|
||||
import { useTheme } from "next-themes";
|
||||
import { VscColorMode } from "react-icons/vsc";
|
||||
|
||||
export const ThemeSwitcher = () => {
|
||||
const { theme, setTheme } = useTheme()
|
||||
const { theme, setTheme } = useTheme();
|
||||
|
||||
const toggle = () => {
|
||||
setTheme(theme === 'light' ? 'dark' : 'light')
|
||||
}
|
||||
const toggle = () => {
|
||||
setTheme(theme === "light" ? "dark" : "light");
|
||||
};
|
||||
|
||||
return (
|
||||
<Button aria-label='Switch Theme' size='sm' onClick={() => toggle()}>
|
||||
{theme === 'light' ? (
|
||||
<VscColorMode style={{ fill: 'black' }} size={20} />
|
||||
) : (
|
||||
<VscColorMode size={20} key={'dark'} />
|
||||
)}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Button aria-label="Switch Theme" size="sm" onPress={() => toggle()}>
|
||||
{theme === "light" ? (
|
||||
<VscColorMode style={{ fill: "black" }} size={20} />
|
||||
) : (
|
||||
<VscColorMode size={20} key={"dark"} />
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
+36
-36
@@ -1,40 +1,40 @@
|
||||
import { useState } from 'react'
|
||||
import useYears from '@/hooks/useYears'
|
||||
import { useState } from "react";
|
||||
import useYears from "@/hooks/useYears";
|
||||
|
||||
export const useAppState = () => {
|
||||
const [flPdfLink, setflPdfLink] = useState<string>('')
|
||||
const [utPdfLink, setutPdfLink] = useState<string>('')
|
||||
const [flZipLink, setflZipLink] = useState<string>('')
|
||||
const [utZipLink, setutZipLink] = useState<string>('')
|
||||
const [flMp3Link, setflMp3Link] = useState<string>('')
|
||||
const [selectedSubject, setSelectedSubject] = useState<string>('')
|
||||
const [selectedYear, setSelectedYear] = useState<string>('')
|
||||
const [selectedPeriod, setSelectedPeriod] = useState<string>('')
|
||||
const [selectedLevel, setSelectedLevel] = useState<string>('')
|
||||
const [years, setYears] = useState<string[]>([])
|
||||
const [flPdfLink, setflPdfLink] = useState<string>("");
|
||||
const [utPdfLink, setutPdfLink] = useState<string>("");
|
||||
const [flZipLink, setflZipLink] = useState<string>("");
|
||||
const [utZipLink, setutZipLink] = useState<string>("");
|
||||
const [flMp3Link, setflMp3Link] = useState<string>("");
|
||||
const [selectedSubject, setSelectedSubject] = useState<string>("");
|
||||
const [selectedYear, setSelectedYear] = useState<string>("");
|
||||
const [selectedPeriod, setSelectedPeriod] = useState<string>("");
|
||||
const [selectedLevel, setSelectedLevel] = useState<string>("");
|
||||
const [years, setYears] = useState<string[]>([]);
|
||||
|
||||
useYears(setYears)
|
||||
useYears(setYears);
|
||||
|
||||
return {
|
||||
flPdfLink,
|
||||
setflPdfLink,
|
||||
utPdfLink,
|
||||
setutPdfLink,
|
||||
flZipLink,
|
||||
setflZipLink,
|
||||
utZipLink,
|
||||
setutZipLink,
|
||||
flMp3Link,
|
||||
setflMp3Link,
|
||||
selectedSubject,
|
||||
setSelectedSubject,
|
||||
selectedYear,
|
||||
setSelectedYear,
|
||||
selectedPeriod,
|
||||
setSelectedPeriod,
|
||||
selectedLevel,
|
||||
setSelectedLevel,
|
||||
years,
|
||||
setYears,
|
||||
}
|
||||
}
|
||||
return {
|
||||
flPdfLink,
|
||||
setflPdfLink,
|
||||
utPdfLink,
|
||||
setutPdfLink,
|
||||
flZipLink,
|
||||
setflZipLink,
|
||||
utZipLink,
|
||||
setutZipLink,
|
||||
flMp3Link,
|
||||
setflMp3Link,
|
||||
selectedSubject,
|
||||
setSelectedSubject,
|
||||
selectedYear,
|
||||
setSelectedYear,
|
||||
selectedPeriod,
|
||||
setSelectedPeriod,
|
||||
selectedLevel,
|
||||
setSelectedLevel,
|
||||
years,
|
||||
setYears,
|
||||
};
|
||||
};
|
||||
|
||||
+10
-10
@@ -1,14 +1,14 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function useYears(
|
||||
setYears: React.Dispatch<React.SetStateAction<string[]>>
|
||||
setYears: React.Dispatch<React.SetStateAction<string[]>>,
|
||||
) {
|
||||
useEffect(() => {
|
||||
const currentYear = new Date().getFullYear()
|
||||
const availableYears: string[] = []
|
||||
for (let year = currentYear; year >= 2013; year--) {
|
||||
availableYears.push(year.toString())
|
||||
}
|
||||
setYears(availableYears)
|
||||
}, [setYears])
|
||||
useEffect(() => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const availableYears: string[] = [];
|
||||
for (let year = currentYear; year >= 2013; year--) {
|
||||
availableYears.push(year.toString());
|
||||
}
|
||||
setYears(availableYears);
|
||||
}, [setYears]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Button } from "@heroui/button";
|
||||
import { useRouter } from "next/router";
|
||||
import { Footer } from "@/components/Footer";
|
||||
|
||||
export default function ErrorPage() {
|
||||
const router = useRouter();
|
||||
|
||||
const handleBack = () => {
|
||||
router.push("/");
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<main className="dark:bg-[#121212] text-foreground bg-background py-5">
|
||||
<h1 className="text-7xl font-bold text-blue-400 text-center mt-16">
|
||||
404
|
||||
</h1>
|
||||
<div className="flex min-h-screen flex-col items-center justify-between">
|
||||
<div className="container mx-auto">
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<div className="mt-5 mb-3">
|
||||
<div className="text-2xl font-semibold text-gray-600">
|
||||
<p className="mt-2">Az keresett oldal nem található.</p>
|
||||
<p className="mt-8 text-center">
|
||||
<Button color="primary" onPress={handleBack}>
|
||||
Vissza
|
||||
</Button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
+25
-27
@@ -1,32 +1,30 @@
|
||||
import { ThemeProvider as NextThemesProvider } from 'next-themes'
|
||||
import { Analytics } from '@vercel/analytics/react'
|
||||
import { NextUIProvider } from '@nextui-org/react'
|
||||
import { Inter } from 'next/font/google'
|
||||
import type { AppProps } from 'next/app'
|
||||
import Head from 'next/head'
|
||||
import '@/styles/globals.css'
|
||||
import { HeroUIProvider } from "@heroui/react";
|
||||
import type { AppProps } from "next/app";
|
||||
import { Inter } from "next/font/google";
|
||||
import Head from "next/head";
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
||||
import "@/styles/globals.css";
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ['latin'],
|
||||
variable: '--font-inter',
|
||||
})
|
||||
subsets: ["latin"],
|
||||
variable: "--font-inter",
|
||||
});
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<>
|
||||
<Analytics />
|
||||
<Head>
|
||||
<title>Érettségi kereső</title>
|
||||
</Head>
|
||||
<NextUIProvider className={`${inter.variable} font-sans`}>
|
||||
<NextThemesProvider
|
||||
attribute='class'
|
||||
defaultTheme='dark'
|
||||
enableSystem={true}
|
||||
>
|
||||
<Component {...pageProps} />
|
||||
</NextThemesProvider>
|
||||
</NextUIProvider>
|
||||
</>
|
||||
)
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Érettségi kereső</title>
|
||||
</Head>
|
||||
<HeroUIProvider className={`${inter.variable} font-sans`}>
|
||||
<NextThemesProvider
|
||||
attribute="class"
|
||||
defaultTheme="dark"
|
||||
enableSystem={true}
|
||||
>
|
||||
<Component {...pageProps} />
|
||||
</NextThemesProvider>
|
||||
</HeroUIProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+32
-32
@@ -1,35 +1,35 @@
|
||||
import { Html, Head, Main, NextScript } from 'next/document'
|
||||
import { Head, Html, Main, NextScript } from "next/document";
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang='hu'>
|
||||
<Head>
|
||||
<meta name='theme-color' content='#121212' />
|
||||
<meta name='title' content='Érettségi kereső' />
|
||||
<meta name='og:title' content='Érettségi kereső' />
|
||||
<meta property='og:url' content='https://erettsegi.albert.lol' />
|
||||
<meta
|
||||
name='description'
|
||||
content='Egyszerű keresés és letöltés az érettségi feladatsorokhoz. 🏫'
|
||||
/>
|
||||
<meta
|
||||
name='og:description'
|
||||
content='Egyszerű keresés és letöltés az érettségi feladatsorokhoz. 🏫'
|
||||
/>
|
||||
<script
|
||||
defer
|
||||
src="https://analytics.albert.lol/script.js"
|
||||
data-website-id="7b196f47-39c9-4b8e-8dfd-b6e707282eea">
|
||||
</script>
|
||||
<link rel='icon' href='/favicon.ico' />
|
||||
<meta property='image' content='/logo.png' />
|
||||
<meta property='og:image' content='/logo.png' />
|
||||
<meta name='author' content='albert' />
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
return (
|
||||
<Html lang="hu">
|
||||
<Head>
|
||||
<meta name="theme-color" content="#121212" />
|
||||
<meta name="title" content="Érettségi kereső" />
|
||||
<meta name="og:title" content="Érettségi kereső" />
|
||||
<meta property="og:url" content="https://erettsegi.albert.lol" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Egyszerű keresés és letöltés az érettségi feladatsorokhoz. 🏫"
|
||||
/>
|
||||
<meta
|
||||
name="og:description"
|
||||
content="Egyszerű keresés és letöltés az érettségi feladatsorokhoz. 🏫"
|
||||
/>
|
||||
<script
|
||||
defer
|
||||
src="https://analytics.albert.lol/script.js"
|
||||
data-website-id="7b196f47-39c9-4b8e-8dfd-b6e707282eea"
|
||||
></script>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta property="image" content="/logo.png" />
|
||||
<meta property="og:image" content="/logo.png" />
|
||||
<meta name="author" content="albert" />
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
import { Footer } from '@/components/Footer'
|
||||
import { Button } from '@nextui-org/button'
|
||||
import type { GetServerSideProps, GetServerSidePropsContext } from 'next'
|
||||
|
||||
interface ErrorProps {
|
||||
statusCode: number
|
||||
}
|
||||
|
||||
const NotFound: React.FC = () => (
|
||||
<>
|
||||
<p className='mt-2'>Az keresett oldal nem található.</p>
|
||||
<p className='mt-8 text-center'>
|
||||
<Button color='primary' onPress={() => (window.location.href = '/')}>
|
||||
Vissza
|
||||
</Button>
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
|
||||
const Unexpected: React.FC = () => (
|
||||
<>
|
||||
<p className='mt-2'>Váratlan hiba történt.</p>
|
||||
<p className='mt-8 text-center'>
|
||||
<Button color='primary' onPress={() => (window.location.href = '/')}>
|
||||
Vissza
|
||||
</Button>
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
|
||||
const ErrorPage: React.FC<ErrorProps> = ({ statusCode }) => {
|
||||
return (
|
||||
<>
|
||||
<main className='dark:bg-[#121212] text-foreground bg-background py-5'>
|
||||
<h1 className='text-7xl font-bold text-blue-400 text-center mt-16'>
|
||||
{statusCode}
|
||||
</h1>
|
||||
<div className='flex min-h-screen flex-col items-center justify-between'>
|
||||
<div className='container mx-auto'>
|
||||
<div className='flex flex-col items-center justify-center'>
|
||||
<div className='mt-5 mb-3'>
|
||||
<div className='text-2xl font-semibold text-gray-600'>
|
||||
{(() => {
|
||||
switch (statusCode) {
|
||||
case 404:
|
||||
return <NotFound />
|
||||
default:
|
||||
return <Unexpected />
|
||||
}
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps: GetServerSideProps<ErrorProps> = async (
|
||||
context: GetServerSidePropsContext
|
||||
) => ({
|
||||
props: {
|
||||
statusCode: context.res ? context.res.statusCode : 404,
|
||||
},
|
||||
})
|
||||
|
||||
export default ErrorPage
|
||||
+108
-86
@@ -1,100 +1,122 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
import { subjects } from '@/utils/subjects'
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { subjects } from "@/utils/subjects";
|
||||
|
||||
export default function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
const { vizsgatargy, ev, idoszak, szint } = req.query as {
|
||||
vizsgatargy: string
|
||||
ev: string
|
||||
idoszak: string
|
||||
szint: string
|
||||
}
|
||||
try {
|
||||
const { vizsgatargy, ev, idoszak, szint } = req.query as {
|
||||
vizsgatargy: string;
|
||||
ev: string;
|
||||
idoszak: string;
|
||||
szint: string;
|
||||
};
|
||||
|
||||
const secure = req.headers['x-forwarded-proto'] === 'https'
|
||||
const protocol = secure ? 'https' : 'http'
|
||||
const address = req.headers.host
|
||||
const secure = req.headers["x-forwarded-proto"] === "https";
|
||||
const protocol = secure ? "https" : "http";
|
||||
const address = req.headers.host;
|
||||
|
||||
const baseUrl = `https://dload-oktatas.educatio.hu/erettsegi/feladatok_${ev}${idoszak}_${szint}/`
|
||||
const proxiedUrl = `${protocol}://${address}/api/proxy?link=${encodeURI(
|
||||
baseUrl
|
||||
)}`
|
||||
const baseUrl = `https://dload-oktatas.educatio.hu/erettsegi/feladatok_${ev}${idoszak}_${szint}/`;
|
||||
const proxiedUrl = `${protocol}://${address}/api/proxy?link=${encodeURI(
|
||||
baseUrl,
|
||||
)}`;
|
||||
|
||||
const missingParams = []
|
||||
if (!ev) missingParams.push('ev')
|
||||
if (!szint) missingParams.push('szint')
|
||||
if (!idoszak) missingParams.push('idoszak')
|
||||
if (!vizsgatargy) missingParams.push('vizsgatargy')
|
||||
const missingParams = [];
|
||||
if (!ev) missingParams.push("ev");
|
||||
if (!szint) missingParams.push("szint");
|
||||
if (!idoszak) missingParams.push("idoszak");
|
||||
if (!vizsgatargy) missingParams.push("vizsgatargy");
|
||||
|
||||
if (missingParams.length > 0) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: `Hiányzó paraméterek: ${missingParams.join(', ')}` })
|
||||
}
|
||||
if (missingParams.length > 0) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: `Hiányzó paraméterek: ${missingParams.join(", ")}` });
|
||||
}
|
||||
|
||||
if (ev <= '2012') {
|
||||
return res.status(400).json({ error: 'Érvénytelen év' })
|
||||
}
|
||||
if (ev <= "2012") {
|
||||
return res.status(400).json({ error: "Érvénytelen év" });
|
||||
}
|
||||
|
||||
const validSubjects = subjects.map((subject) => subject.value)
|
||||
if (!vizsgatargy || !validSubjects.includes(vizsgatargy)) {
|
||||
return res.status(400).json({ error: 'Érvénytelen vizsgatárgy' })
|
||||
}
|
||||
const validSubjects = subjects.map((subject) => subject.value);
|
||||
if (!vizsgatargy || !validSubjects.includes(vizsgatargy)) {
|
||||
return res.status(400).json({ error: "Érvénytelen vizsgatárgy" });
|
||||
}
|
||||
|
||||
let honap: string
|
||||
switch (idoszak) {
|
||||
case 'osz':
|
||||
honap = 'okt'
|
||||
break
|
||||
case 'tavasz':
|
||||
honap = 'maj'
|
||||
break
|
||||
default:
|
||||
return res.status(400).json({ error: 'Érvénytelen időszak' })
|
||||
}
|
||||
let honap: string;
|
||||
switch (idoszak) {
|
||||
case "osz":
|
||||
honap = "okt";
|
||||
break;
|
||||
case "tavasz":
|
||||
honap = "maj";
|
||||
break;
|
||||
default:
|
||||
return res.status(400).json({ error: "Érvénytelen időszak" });
|
||||
}
|
||||
|
||||
let prefix: string
|
||||
switch (szint) {
|
||||
case 'emelt':
|
||||
prefix = `e_${vizsgatargy}`
|
||||
break
|
||||
case 'kozep':
|
||||
prefix = `k_${vizsgatargy}`
|
||||
break
|
||||
default:
|
||||
return res.status(400).json({ error: 'Érvénytelen szint' })
|
||||
}
|
||||
let prefix: string;
|
||||
switch (szint) {
|
||||
case "emelt":
|
||||
prefix = `e_${vizsgatargy}`;
|
||||
break;
|
||||
case "kozep":
|
||||
prefix = `k_${vizsgatargy}`;
|
||||
break;
|
||||
default:
|
||||
return res.status(400).json({ error: "Érvénytelen szint" });
|
||||
}
|
||||
|
||||
const feladat = 'fl'
|
||||
const utmutato = 'ut'
|
||||
const forras = 'for'
|
||||
const megoldas = 'meg'
|
||||
const shortev = ev.slice(-2)
|
||||
const feladat = "fl";
|
||||
const utmutato = "ut";
|
||||
const forras = "for";
|
||||
const megoldas = "meg";
|
||||
const shortev = ev.slice(-2);
|
||||
|
||||
let flPdfUrl, utPdfUrl, flZipUrl, utZipUrl, flMp3Url
|
||||
switch (vizsgatargy) {
|
||||
case 'inf':
|
||||
case 'infoism':
|
||||
case 'digkult':
|
||||
flZipUrl = `${baseUrl}${prefix}${forras}_${shortev}${honap}_${feladat}.zip`
|
||||
flPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`
|
||||
utZipUrl = `${baseUrl}${prefix}${megoldas}_${shortev}${honap}_${utmutato}.zip`
|
||||
utPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`
|
||||
break
|
||||
case 'angol':
|
||||
case 'nemet':
|
||||
flPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`
|
||||
utPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`
|
||||
flMp3Url = `${baseUrl}${prefix}_${shortev}${honap}_${feladat}.mp3`
|
||||
break
|
||||
default:
|
||||
flPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`
|
||||
utPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`
|
||||
break
|
||||
}
|
||||
let flPdfUrl: string | undefined,
|
||||
utPdfUrl: string | undefined,
|
||||
flZipUrl: string | undefined,
|
||||
utZipUrl: string | undefined,
|
||||
flMp3Url: string | undefined;
|
||||
switch (vizsgatargy) {
|
||||
case "inf":
|
||||
case "infoism":
|
||||
case "digkult":
|
||||
flZipUrl = `${baseUrl}${prefix}${forras}_${shortev}${honap}_${feladat}.zip`;
|
||||
flPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`;
|
||||
utZipUrl = `${baseUrl}${prefix}${megoldas}_${shortev}${honap}_${utmutato}.zip`;
|
||||
utPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`;
|
||||
break;
|
||||
case "angol":
|
||||
case "nemet":
|
||||
flPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`;
|
||||
utPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`;
|
||||
flMp3Url = `${baseUrl}${prefix}_${shortev}${honap}_${feladat}.mp3`;
|
||||
break;
|
||||
default:
|
||||
flPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`;
|
||||
utPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`;
|
||||
break;
|
||||
}
|
||||
|
||||
res.setHeader('Cache-Control', 's-maxage=31536000')
|
||||
res.status(200).json({ flPdfUrl, utPdfUrl, flZipUrl, utZipUrl, flMp3Url })
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Internal Server Error', message: error })
|
||||
}
|
||||
res.setHeader("Cache-Control", "s-maxage=31536000");
|
||||
res.status(200).json({ flPdfUrl, utPdfUrl, flZipUrl, utZipUrl, flMp3Url });
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
let causeCode: string | undefined;
|
||||
if (e.cause && typeof e.cause === "object" && "code" in e.cause) {
|
||||
causeCode = String((e.cause as { code: unknown }).code);
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
error: "Internal Server Error",
|
||||
message: e.message,
|
||||
cause: causeCode,
|
||||
stack: process.env.NODE_ENV === "development" ? e.stack : undefined,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({
|
||||
error: "Internal Server Error",
|
||||
message: "An unexpected error occurred",
|
||||
details: String(e),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+68
-36
@@ -1,45 +1,77 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { Agent, fetch } from "undici";
|
||||
|
||||
const insecureAgent = new Agent({
|
||||
connect: {
|
||||
rejectUnauthorized: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
const { link } = req.query as { link: string }
|
||||
let missingParam: string | null = null
|
||||
if (!link) {
|
||||
missingParam = 'link'
|
||||
}
|
||||
const { link } = req.query as { link: string };
|
||||
let missingParam: string | null = null;
|
||||
if (!link) {
|
||||
missingParam = "link";
|
||||
}
|
||||
|
||||
if (missingParam) {
|
||||
return res.status(400).json({ error: `Hiányzó paraméter: ${missingParam}` })
|
||||
}
|
||||
if (missingParam) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: `Hiányzó paraméter: ${missingParam}` });
|
||||
}
|
||||
|
||||
const domain = link.split('/')[2]
|
||||
if (domain !== 'dload-oktatas.educatio.hu') {
|
||||
return res.status(400).json({ error: 'Érvénytelen link' })
|
||||
}
|
||||
const domain = link.split("/")[2];
|
||||
if (domain !== "dload-oktatas.educatio.hu") {
|
||||
return res.status(400).json({ error: "Érvénytelen link" });
|
||||
}
|
||||
|
||||
try {
|
||||
res.setHeader('Cache-Control', 's-maxage=31536000')
|
||||
const response = await fetch(link, { method: 'GET' })
|
||||
const contentType = response.headers.get('content-type')
|
||||
try {
|
||||
res.setHeader("Cache-Control", "s-maxage=31536000");
|
||||
|
||||
if (contentType == 'application/pdf') {
|
||||
const filename = link.split('/').pop() ?? 'document.pdf'
|
||||
res.setHeader('Content-Type', contentType)
|
||||
res.setHeader('Content-Disposition', `inline; filename="${filename}"`)
|
||||
}
|
||||
const response = await fetch(link, {
|
||||
method: "GET",
|
||||
dispatcher: insecureAgent,
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const arrayBuffer: ArrayBuffer = await response.arrayBuffer()
|
||||
const buffer: Buffer = Buffer.from(arrayBuffer)
|
||||
res.send(buffer)
|
||||
} else {
|
||||
res
|
||||
.status(response.status)
|
||||
.json({ error: 'Hiba történt a lekérés során.' })
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Internal Server Error', message: error })
|
||||
}
|
||||
const contentType = response.headers.get("content-type");
|
||||
|
||||
if (contentType === "application/pdf") {
|
||||
const filename = link.split("/").pop() ?? "document.pdf";
|
||||
res.setHeader("Content-Type", contentType);
|
||||
res.setHeader("Content-Disposition", `inline; filename="${filename}"`);
|
||||
}
|
||||
|
||||
if (response.ok) {
|
||||
const arrayBuffer: ArrayBuffer = await response.arrayBuffer();
|
||||
const buffer: Buffer = Buffer.from(arrayBuffer);
|
||||
res.send(buffer);
|
||||
} else {
|
||||
res
|
||||
.status(response.status)
|
||||
.json({ error: "Hiba történt a lekérés során." });
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
let causeCode: string | undefined;
|
||||
if (e.cause && typeof e.cause === "object" && "code" in e.cause) {
|
||||
causeCode = String((e.cause as { code: unknown }).code);
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
error: "Internal Server Error",
|
||||
message: e.message,
|
||||
cause: causeCode,
|
||||
stack: process.env.NODE_ENV === "development" ? e.stack : undefined,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({
|
||||
error: "Internal Server Error",
|
||||
message: "An unexpected error occurred",
|
||||
details: String(e),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+50
-30
@@ -1,40 +1,60 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
const { link } = req.query as { link: string }
|
||||
let missingParam: string | null = null
|
||||
const { link } = req.query as { link: string };
|
||||
let missingParam: string | null = null;
|
||||
|
||||
if (!link) {
|
||||
missingParam = 'link'
|
||||
}
|
||||
if (!link) {
|
||||
missingParam = "link";
|
||||
}
|
||||
|
||||
if (missingParam) {
|
||||
return res.status(400).json({ error: `Hiányzó paraméter: ${missingParam}` })
|
||||
}
|
||||
if (missingParam) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: `Hiányzó paraméter: ${missingParam}` });
|
||||
}
|
||||
|
||||
const domain = link.split('/')[2]
|
||||
if (
|
||||
domain !== 'localhost:3000' &&
|
||||
domain !== 'erettsegi.albert.lol' &&
|
||||
domain !== 'dload-oktatas.educatio.hu'
|
||||
) {
|
||||
return res.status(400).json({ error: 'Érvénytelen link' })
|
||||
}
|
||||
const domain = link.split("/")[2];
|
||||
if (
|
||||
domain !== "localhost:3000" &&
|
||||
domain !== "erettsegi.albert.lol" &&
|
||||
domain !== "dload-oktatas.educatio.hu"
|
||||
) {
|
||||
return res.status(400).json({ error: "Érvénytelen link" });
|
||||
}
|
||||
|
||||
try {
|
||||
const { protocol, host } = new URL(link)
|
||||
if (!protocol || !host) {
|
||||
return res.status(400).json({ error: 'Érvénytelen link' })
|
||||
}
|
||||
try {
|
||||
const { protocol, host } = new URL(link);
|
||||
if (!protocol || !host) {
|
||||
return res.status(400).json({ error: "Érvénytelen link" });
|
||||
}
|
||||
|
||||
const response = await fetch(link, { method: 'HEAD' })
|
||||
const response = await fetch(link, { method: "HEAD" });
|
||||
|
||||
const status = response.status
|
||||
res.status(200).json({ status })
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Internal Server Error', message: error })
|
||||
}
|
||||
const status = response.status;
|
||||
res.status(200).json({ status });
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
let causeCode: string | undefined;
|
||||
if (e.cause && typeof e.cause === "object" && "code" in e.cause) {
|
||||
causeCode = String((e.cause as { code: unknown }).code);
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
error: "Internal Server Error",
|
||||
message: e.message,
|
||||
cause: causeCode,
|
||||
stack: process.env.NODE_ENV === "development" ? e.stack : undefined,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({
|
||||
error: "Internal Server Error",
|
||||
message: "An unexpected error occurred",
|
||||
details: String(e),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+122
-112
@@ -1,119 +1,129 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import { ButtonGroup, Divider } from '@nextui-org/react'
|
||||
import { PdfButton, ZipButton, Mp3Button } from '@/components/Buttons'
|
||||
import { Footer } from '@/components/Footer'
|
||||
import { fetchData } from '@/utils/fetch'
|
||||
import useYears from '@/hooks/useYears'
|
||||
import { useAppState } from '@/hooks/useState'
|
||||
import { ButtonGroup, Divider } from "@heroui/react";
|
||||
import { useEffect } from "react";
|
||||
import { Mp3Button, PdfButton, ZipButton } from "@/components/Buttons";
|
||||
import { Footer } from "@/components/Footer";
|
||||
import {
|
||||
SubjectSelector,
|
||||
YearSelector,
|
||||
PeriodSelector,
|
||||
LevelSelector,
|
||||
} from '@/components/Selectors'
|
||||
import { subjects } from '@/utils/subjects'
|
||||
LevelSelector,
|
||||
PeriodSelector,
|
||||
SubjectSelector,
|
||||
YearSelector,
|
||||
} from "@/components/Selectors";
|
||||
import { useAppState } from "@/hooks/useState";
|
||||
import useYears from "@/hooks/useYears";
|
||||
import { fetchData } from "@/utils/fetch";
|
||||
import { subjects } from "@/utils/subjects";
|
||||
|
||||
export default function Home() {
|
||||
const {
|
||||
flPdfLink,
|
||||
setflPdfLink,
|
||||
utPdfLink,
|
||||
setutPdfLink,
|
||||
flZipLink,
|
||||
setflZipLink,
|
||||
utZipLink,
|
||||
setutZipLink,
|
||||
flMp3Link,
|
||||
setflMp3Link,
|
||||
selectedSubject,
|
||||
setSelectedSubject,
|
||||
selectedYear,
|
||||
setSelectedYear,
|
||||
selectedPeriod,
|
||||
setSelectedPeriod,
|
||||
selectedLevel,
|
||||
setSelectedLevel,
|
||||
years,
|
||||
setYears,
|
||||
} = useAppState()
|
||||
const {
|
||||
flPdfLink,
|
||||
setflPdfLink,
|
||||
utPdfLink,
|
||||
setutPdfLink,
|
||||
flZipLink,
|
||||
setflZipLink,
|
||||
utZipLink,
|
||||
setutZipLink,
|
||||
flMp3Link,
|
||||
setflMp3Link,
|
||||
selectedSubject,
|
||||
setSelectedSubject,
|
||||
selectedYear,
|
||||
setSelectedYear,
|
||||
selectedPeriod,
|
||||
setSelectedPeriod,
|
||||
selectedLevel,
|
||||
setSelectedLevel,
|
||||
years,
|
||||
setYears,
|
||||
} = useAppState();
|
||||
|
||||
useYears(setYears)
|
||||
useYears(setYears);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedLevel && selectedPeriod && selectedSubject && selectedYear) {
|
||||
void fetchData(
|
||||
selectedSubject,
|
||||
selectedYear,
|
||||
selectedPeriod,
|
||||
selectedLevel,
|
||||
setflZipLink,
|
||||
setutZipLink,
|
||||
setflPdfLink,
|
||||
setutPdfLink,
|
||||
setflMp3Link,
|
||||
)
|
||||
}
|
||||
}, [selectedLevel, selectedPeriod, selectedSubject, selectedYear])
|
||||
useEffect(() => {
|
||||
if (selectedLevel && selectedPeriod && selectedSubject && selectedYear) {
|
||||
void fetchData(
|
||||
selectedSubject,
|
||||
selectedYear,
|
||||
selectedPeriod,
|
||||
selectedLevel,
|
||||
setflZipLink,
|
||||
setutZipLink,
|
||||
setflPdfLink,
|
||||
setutPdfLink,
|
||||
setflMp3Link,
|
||||
);
|
||||
}
|
||||
}, [
|
||||
selectedLevel,
|
||||
selectedPeriod,
|
||||
selectedSubject,
|
||||
selectedYear,
|
||||
setutPdfLink,
|
||||
setflZipLink,
|
||||
setutZipLink,
|
||||
setflPdfLink,
|
||||
setflMp3Link,
|
||||
]);
|
||||
|
||||
return (
|
||||
<main className='dark:bg-[#121212] text-foreground bg-background py-5'>
|
||||
<h1 className='text-4xl font-bold text-blue-400 text-center mt-16'>
|
||||
Érettségi kereső
|
||||
</h1>
|
||||
<div className='flex min-h-screen flex-col items-center justify-between'>
|
||||
<div className='container mx-auto'>
|
||||
<div className='flex flex-col items-center justify-center'>
|
||||
<div className='mt-5 mb-3'>
|
||||
<SubjectSelector
|
||||
selectedSubject={selectedSubject}
|
||||
setSelectedSubject={setSelectedSubject}
|
||||
subjects={subjects}
|
||||
/>
|
||||
</div>
|
||||
<div className='mb-3'>
|
||||
<YearSelector
|
||||
selectedYear={selectedYear}
|
||||
setSelectedYear={setSelectedYear}
|
||||
years={years}
|
||||
/>
|
||||
</div>
|
||||
<div className='mb-3'>
|
||||
<PeriodSelector
|
||||
selectedPeriod={selectedPeriod}
|
||||
setSelectedPeriod={setSelectedPeriod}
|
||||
/>
|
||||
</div>
|
||||
<div className='mb-3'>
|
||||
<LevelSelector
|
||||
selectedLevel={selectedLevel}
|
||||
setSelectedLevel={setSelectedLevel}
|
||||
/>
|
||||
</div>
|
||||
<div className='space-x-3'>
|
||||
<ButtonGroup>
|
||||
<PdfButton label='Feladatlap' link={flPdfLink} />
|
||||
<Divider orientation='vertical' />
|
||||
<PdfButton label='Útmutató' link={utPdfLink} />
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
{['inf', 'infoism', 'digkult'].includes(selectedSubject) && (
|
||||
<div className='space-x-3'>
|
||||
<ButtonGroup>
|
||||
<ZipButton label='Forrás' link={flZipLink} />
|
||||
<Divider orientation='vertical' />
|
||||
<ZipButton label='Megoldás' link={utZipLink} />
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
)}
|
||||
{['angol', 'nemet'].includes(selectedSubject) && (
|
||||
<div className='space-x-3'>
|
||||
<Mp3Button label='Hang' link={flMp3Link} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
)
|
||||
return (
|
||||
<main className="dark:bg-[#121212] text-foreground bg-background py-5">
|
||||
<h1 className="text-4xl font-bold text-blue-400 text-center mt-16">
|
||||
Érettségi kereső
|
||||
</h1>
|
||||
<div className="flex min-h-screen flex-col items-center justify-between">
|
||||
<div className="container mx-auto">
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<div className="mt-5 mb-3">
|
||||
<SubjectSelector
|
||||
selectedSubject={selectedSubject}
|
||||
setSelectedSubject={setSelectedSubject}
|
||||
subjects={subjects}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<YearSelector
|
||||
selectedYear={selectedYear}
|
||||
setSelectedYear={setSelectedYear}
|
||||
years={years}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<PeriodSelector
|
||||
selectedPeriod={selectedPeriod}
|
||||
setSelectedPeriod={setSelectedPeriod}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<LevelSelector
|
||||
selectedLevel={selectedLevel}
|
||||
setSelectedLevel={setSelectedLevel}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-x-3">
|
||||
<ButtonGroup>
|
||||
<PdfButton label="Feladatlap" link={flPdfLink} />
|
||||
<Divider orientation="vertical" />
|
||||
<PdfButton label="Útmutató" link={utPdfLink} />
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
{["inf", "infoism", "digkult"].includes(selectedSubject) && (
|
||||
<div className="space-x-3">
|
||||
<ButtonGroup>
|
||||
<ZipButton label="Forrás" link={flZipLink} />
|
||||
<Divider orientation="vertical" />
|
||||
<ZipButton label="Megoldás" link={utZipLink} />
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
)}
|
||||
{["angol", "nemet"].includes(selectedSubject) && (
|
||||
<div className="space-x-3">
|
||||
<Mp3Button label="Hang" link={flMp3Link} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
+19
-7
@@ -1,10 +1,22 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@import "tailwindcss";
|
||||
@plugin './hero.ts';
|
||||
|
||||
@source '../../node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}';
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@layer base {
|
||||
*,
|
||||
::after,
|
||||
::before,
|
||||
::backdrop,
|
||||
::file-selector-button {
|
||||
border-color: var(--color-gray-200, currentcolor);
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #121212;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #121212;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
import { heroui } from "@heroui/react";
|
||||
export default heroui();
|
||||
+38
-38
@@ -1,45 +1,45 @@
|
||||
export const fetchData = async (
|
||||
selectedSubject: string,
|
||||
selectedYear: string,
|
||||
selectedPeriod: string,
|
||||
selectedLevel: string,
|
||||
setflZipLink: (link: string) => void,
|
||||
setutZipLink: (link: string) => void,
|
||||
setflPdfLink: (link: string) => void,
|
||||
setutPdfLink: (link: string) => void,
|
||||
setflMp3Link: (link: string) => void
|
||||
selectedSubject: string,
|
||||
selectedYear: string,
|
||||
selectedPeriod: string,
|
||||
selectedLevel: string,
|
||||
setflZipLink: (link: string) => void,
|
||||
setutZipLink: (link: string) => void,
|
||||
setflPdfLink: (link: string) => void,
|
||||
setutPdfLink: (link: string) => void,
|
||||
setflMp3Link: (link: string) => void,
|
||||
) => {
|
||||
try {
|
||||
const url = `/api/erettsegi?vizsgatargy=${selectedSubject}&ev=${selectedYear}&idoszak=${selectedPeriod}&szint=${selectedLevel}`
|
||||
try {
|
||||
const url = `/api/erettsegi?vizsgatargy=${selectedSubject}&ev=${selectedYear}&idoszak=${selectedPeriod}&szint=${selectedLevel}`;
|
||||
|
||||
const response = await fetch(url)
|
||||
const response = await fetch(url);
|
||||
|
||||
if (response.ok) {
|
||||
const data = (await response.json()) as {
|
||||
flZipUrl: string
|
||||
utZipUrl: string
|
||||
flPdfUrl: string
|
||||
utPdfUrl: string
|
||||
flMp3Url: string
|
||||
}
|
||||
if (response.ok) {
|
||||
const data = (await response.json()) as {
|
||||
flZipUrl: string;
|
||||
utZipUrl: string;
|
||||
flPdfUrl: string;
|
||||
utPdfUrl: string;
|
||||
flMp3Url: string;
|
||||
};
|
||||
|
||||
if (data.utZipUrl && data.flZipUrl) {
|
||||
setflZipLink(data.flZipUrl)
|
||||
setutZipLink(data.utZipUrl)
|
||||
}
|
||||
if (data.utZipUrl && data.flZipUrl) {
|
||||
setflZipLink(data.flZipUrl);
|
||||
setutZipLink(data.utZipUrl);
|
||||
}
|
||||
|
||||
if (data.utPdfUrl && data.flPdfUrl) {
|
||||
setflPdfLink(data.flPdfUrl)
|
||||
setutPdfLink(data.utPdfUrl)
|
||||
}
|
||||
if (data.utPdfUrl && data.flPdfUrl) {
|
||||
setflPdfLink(data.flPdfUrl);
|
||||
setutPdfLink(data.utPdfUrl);
|
||||
}
|
||||
|
||||
if (data.flMp3Url) {
|
||||
setflMp3Link(data.flMp3Url)
|
||||
}
|
||||
} else {
|
||||
console.error('Hiba történt az API hívás során.')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Hiba történt az API hívás során.', error)
|
||||
}
|
||||
}
|
||||
if (data.flMp3Url) {
|
||||
setflMp3Link(data.flMp3Url);
|
||||
}
|
||||
} else {
|
||||
console.error("Hiba történt az API hívás során.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Hiba történt az API hívás során.", error);
|
||||
}
|
||||
};
|
||||
|
||||
+12
-12
@@ -1,17 +1,17 @@
|
||||
export interface SelectorProps {
|
||||
years: string[]
|
||||
subjects: { label: string; value: string }[]
|
||||
selectedSubject: string
|
||||
selectedYear: string
|
||||
selectedPeriod: string
|
||||
selectedLevel: string
|
||||
setSelectedSubject: React.Dispatch<React.SetStateAction<string>>
|
||||
setSelectedYear: React.Dispatch<React.SetStateAction<string>>
|
||||
setSelectedPeriod: React.Dispatch<React.SetStateAction<string>>
|
||||
setSelectedLevel: React.Dispatch<React.SetStateAction<string>>
|
||||
years: string[];
|
||||
subjects: { label: string; value: string }[];
|
||||
selectedSubject: string;
|
||||
selectedYear: string;
|
||||
selectedPeriod: string;
|
||||
selectedLevel: string;
|
||||
setSelectedSubject: React.Dispatch<React.SetStateAction<string>>;
|
||||
setSelectedYear: React.Dispatch<React.SetStateAction<string>>;
|
||||
setSelectedPeriod: React.Dispatch<React.SetStateAction<string>>;
|
||||
setSelectedLevel: React.Dispatch<React.SetStateAction<string>>;
|
||||
}
|
||||
|
||||
export interface ButtonProps {
|
||||
label: string
|
||||
link: string
|
||||
label: string;
|
||||
link: string;
|
||||
}
|
||||
|
||||
+15
-15
@@ -1,16 +1,16 @@
|
||||
export const subjects = [
|
||||
{ value: 'magyir', label: 'Magyar nyelv és irodalom' },
|
||||
{ value: 'mat', label: 'Matematika' },
|
||||
{ value: 'tort', label: 'Történelem' },
|
||||
{ value: 'angol', label: 'Angol nyelv' },
|
||||
{ value: 'nemet', label: 'Német nyelv' },
|
||||
{ value: 'inf', label: 'Informatika' },
|
||||
{ value: 'digkult', label: 'Digitális kultúra' },
|
||||
{ value: 'bio', label: 'Biológia' },
|
||||
{ value: 'infoism', label: 'Informatikai ismeretek' },
|
||||
{ value: 'ker', label: 'Kereskedelmi ismeretek' },
|
||||
{ value: 'kozg', label: 'Közgazdasági ismeretek' },
|
||||
{ value: 'kem', label: 'Kémia' },
|
||||
{ value: 'fldr', label: 'Földrajz' },
|
||||
{ value: 'fiz', label: 'Fizika' },
|
||||
]
|
||||
{ value: "magyir", label: "Magyar nyelv és irodalom" },
|
||||
{ value: "mat", label: "Matematika" },
|
||||
{ value: "tort", label: "Történelem" },
|
||||
{ value: "angol", label: "Angol nyelv" },
|
||||
{ value: "nemet", label: "Német nyelv" },
|
||||
{ value: "inf", label: "Informatika" },
|
||||
{ value: "digkult", label: "Digitális kultúra" },
|
||||
{ value: "bio", label: "Biológia" },
|
||||
{ value: "infoism", label: "Informatikai ismeretek" },
|
||||
{ value: "ker", label: "Kereskedelmi ismeretek" },
|
||||
{ value: "kozg", label: "Közgazdasági ismeretek" },
|
||||
{ value: "kem", label: "Kémia" },
|
||||
{ value: "fldr", label: "Földrajz" },
|
||||
{ value: "fiz", label: "Fizika" },
|
||||
];
|
||||
|
||||
+7
-7
@@ -1,8 +1,8 @@
|
||||
export type ButtonColor =
|
||||
| 'primary'
|
||||
| 'danger'
|
||||
| 'default'
|
||||
| 'secondary'
|
||||
| 'success'
|
||||
| 'warning'
|
||||
| undefined
|
||||
| "primary"
|
||||
| "danger"
|
||||
| "default"
|
||||
| "secondary"
|
||||
| "success"
|
||||
| "warning"
|
||||
| undefined;
|
||||
|
||||
Reference in New Issue
Block a user