Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@
"@tailwindcss/postcss": "^4",
"@types/negotiator": "^0.6.4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/react": "^19.1.9",
"@types/react-dom": "^19.1.7",
Comment on lines +55 to +56
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package.json changes pin @types/react and @types/react-dom to specific patch versions (^19.1.9 and ^19.1.7), but the existing versions already used caret ranges (^19) which would have automatically resolved to compatible versions.

While these changes are technically valid, they're unnecessary and could lead to:

  1. Merge conflicts if other developers update these types
  2. Missing out on bug fixes in patch releases
  3. Inconsistency with the rest of the dependencies which use broader ranges

The original ranges (^19 and ^19) were sufficient and more flexible.

Suggested change
"@types/react": "^19.1.9",
"@types/react-dom": "^19.1.7",
"@types/react": "^19",
"@types/react-dom": "^19",

Copilot uses AI. Check for mistakes.
"esbuild": "^0.25.2",
"eslint": "^9",
"eslint-config-next": "15.5.9",
Expand Down
24 changes: 24 additions & 0 deletions src/app/(app)/[lang]/sport/sportpalyaTamogatas/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { getDictionary } from '@/get-dictionary';
import type { Locale } from '@/i18n-config';
import { PageHeader } from '@/components/common/PageHeader';
import GymSupportContent from './components/GymSupportContent';
type SportpalyaTamogatasPageProps = {
params: Promise<{ lang: Locale }>;
};
export default async function SportpalyaTamogatasPage({
params,
}: SportpalyaTamogatasPageProps) {
const { lang } = await params;
const dictionary = await getDictionary(lang);
return (
<div className="min-h-screen bg-gray-50">
<div className="container mx-auto px-4 py-8">
<main className="container mx-auto py-10 px-4">
<GymSupportContent
content={dictionary.sport.sportpalyaTamogatas}
/>
</main>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import {JSX, ReactNode} from 'react';
import { Card, CardContent } from '@/components/ui/card';
import { PageHeader } from '@/components/common/PageHeader';
import { parseFormattedText } from '@/utils/parseFormattedText';

interface SportteremContentData {
title: string;
description: string;
facilities: {
title: string;
items: string[]
};
conditions: {
title: string;
description: string
};
process: {
title: string;
description: string;
warning: string
};
requiredData: {
title: string;
intro: string;
items: string[]
};
selection: {
title: string;
intro: string;
items: string[];
warning: string
};
usage: {
title: string;
items: string[]
};
costs: {
title: string;
description: string;
items: string[]
};
contact: {
title: string;
description: string
};
footer: string;
}


export default function SportteremContent({ content }: { content: SportteremContentData }) {
return (
<div className="flex flex-col gap-4 md:gap-6 lg:px-4 px-2 py-8">

{/* Introduction */}
<Card className="group hover:shadow-md transition-all duration-300">
<CardContent className="p-3 md:p-6">
<div className="flex flex-col gap-2 md:gap-3">
<Paragraph>
{parseFormattedText(content.description)}
</Paragraph>
</div>
</CardContent>
</Card>

{/* Facilities */}
<Card className="group hover:shadow-md transition-all duration-300">
<CardContent className="p-3 md:p-6">
<div className="flex flex-col gap-2 md:gap-3">
<h3 className="font-bold text-xl leading-tight text-gray-900 group-hover:text-[#862633] transition-colors">
{content.facilities.title}
</h3>
<div className="space-y-2 text-gray-700">
<ul className="list-disc pl-5 space-y-2">
{content.facilities.items.map((item, i) => (
<li key={i}>{parseFormattedText(item)}</li>
))}
</ul>
</div>
</div>
</CardContent>
</Card>

{/* Conditions */}
<Card className="group hover:shadow-md transition-all duration-300">
<CardContent className="p-3 md:p-6">
<div className="flex flex-col gap-2 md:gap-3">
<h3 className="font-bold text-xl leading-tight text-gray-900 group-hover:text-[#862633] transition-colors">
{content.conditions.title}
</h3>
<Paragraph>{parseFormattedText(content.conditions.description)}</Paragraph>
</div>
</CardContent>
</Card>

{/* Process & Deadlines */}
<Card className="group hover:shadow-md transition-all duration-300">
<CardContent className="p-3 md:p-6">
<div className="flex flex-col gap-2 md:gap-3">
<h3 className="font-bold text-xl leading-tight text-gray-900 group-hover:text-[#862633] transition-colors">
{content.process.title}
</h3>
<Paragraph>{parseFormattedText(content.process.description)}</Paragraph>
<div className="mt-4 p-3 bg-gray-50 rounded-lg border border-gray-100 text-sm font-semibold">
{parseFormattedText(content.process.warning)}
</div>
</div>
</CardContent>
</Card>

{/* Required Data */}
<Card className="group hover:shadow-md transition-all duration-300">
<CardContent className="p-3 md:p-6">
<div className="flex flex-col gap-2 md:gap-3">
<h3 className="font-bold text-xl leading-tight text-gray-900 group-hover:text-[#862633] transition-colors">
{content.requiredData.title}
</h3>
<p>{parseFormattedText(content.requiredData.intro)}</p>
<ul className="list-disc pl-5 space-y-1">
{content.requiredData.items.map((item, i) => (
<li key={i}>{parseFormattedText(item)}</li>
))}
</ul>
</div>
</CardContent>
</Card>

{/* Selection Criteria */}
<Card className="group hover:shadow-md transition-all duration-300">
<CardContent className="p-3 md:p-6">
<div className="flex flex-col gap-2 md:gap-3">
<h3 className="font-bold text-xl leading-tight text-gray-900 group-hover:text-[#862633] transition-colors">
{content.selection.title}
</h3>
<p>{parseFormattedText(content.selection.intro)}</p>
<ul className="list-disc pl-5 space-y-1">
{content.selection.items.map((item, i) => (
<li key={i}>{parseFormattedText(item)}</li>
))}
</ul>
<div className="mt-4 p-3 bg-gray-50 rounded-lg border border-gray-100 text-sm font-semibold">
{parseFormattedText(content.selection.warning)}
</div>
</div>
</CardContent>
</Card>

{/* Rules & usage */}
<Card className="group hover:shadow-md transition-all duration-300">
<CardContent className="p-3 md:p-6">
<div className="flex flex-col gap-2 md:gap-3">
<h3 className="font-bold text-xl leading-tight text-gray-900 group-hover:text-[#862633] transition-colors">
{content.usage.title}
</h3>
<ul className="list-disc pl-5 space-y-1">
{content.usage.items.map((item, i) => (
<li key={i}>{parseFormattedText(item)}</li>
))}
</ul>
</div>
</CardContent>
</Card>

{/* Costs */}
<Card className="group hover:shadow-md transition-all duration-300">
<CardContent className="p-3 md:p-6">
<div className="flex flex-col gap-2 md:gap-3">
<h3 className="font-bold text-xl leading-tight text-gray-900 group-hover:text-[#862633] transition-colors">
{content.costs.title}
</h3>
<Paragraph>{parseFormattedText(content.costs.description)}</Paragraph>
<ul className="list-disc pl-5 space-y-1">
{content.costs.items.map((item, i) => (
<li key={i}>{parseFormattedText(item)}</li>
))}
</ul>
</div>
</CardContent>
</Card>

{/* Kapcsolattartás */}
<Card className="group hover:shadow-md transition-all duration-300">
<CardContent className="p-3 md:p-6">
<div className="flex flex-col gap-2 md:gap-3">
<h3 className="font-bold text-xl leading-tight text-gray-900 group-hover:text-[#862633] transition-colors">
{content.contact.title}
</h3>
<Paragraph>{parseFormattedText(content.contact.description)}</Paragraph>
</div>
</CardContent>
</Card>

<p className="text-center text-sm text-gray-400 italic mt-4">{parseFormattedText(content.footer)}</p>

</div>
);
};

function Paragraph({ children }: { children: ReactNode }) {
return (
<div className="prose max-w-none text-gray-700 richtext">
<p>{children}</p>
</div>
);
}
23 changes: 23 additions & 0 deletions src/app/(app)/[lang]/sport/sportterem-igenyles/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getDictionary } from '@/get-dictionary';
import type { Locale } from '@/i18n-config';
import SportteremContent from './components/SportteremContent';
import { PageHeader } from '@/components/common/PageHeader';
type SportteremIgenylesPageProps = {
params: Promise<{ lang: Locale }>;
};
export default async function SportteremIgenylesPage({
params,
}: SportteremIgenylesPageProps) {
const { lang } = await params;
const dictionary = await getDictionary(lang);
return (
<div className="min-h-screen bg-gray-50">
<div className="container mx-auto px-4 py-8">
<PageHeader title={dictionary.sport.sportterem.title} />
<SportteremContent
content={dictionary.sport.sportterem}
/>
</div>
</div>
);
}
4 changes: 2 additions & 2 deletions src/app/(app)/components/navigation-items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@ export function getNavigationItems(lang: string): NavigationItem[] {
"Sportpálya támogatás pályázat",
"Sports field subsidy application"
),
href: "#",
href: link("/sport/sportpalya-tamogatas-palyazat"),
targetBlank: false,
},
{
label: t("Sportterem igénylés", "Gym booking request"),
href: "#",
href: link("/sport/sportterem-igenyles"),
targetBlank: false,
},
{
Expand Down
71 changes: 71 additions & 0 deletions src/dictionaries/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,77 @@
"eszb_website": "ESZB website"
}
},

"sport": {
"sportterem": {
"title": "Gym Application Information",
"description": "The **Sport Division of the Budapest University of Technology and Economics (BME)** and the **University Student Representative Council (EHK)** provide an opportunity for sports teams and groups of friends to train in the university's sports facilities at a discounted rate."
,
"facilities": {
"title": "Available Sports Facilities",
"items": [
"**BME Sports Center** (Bertalan Lajos street 4-6, Building ÉL) rooms.",
"**Dormitory gyms:** Kármán Tódor Dormitory and Bercsényi 28-30 Dormitory gyms."
]
},
"conditions": {
"title": "Conditions for Discounted Rental",
"description": "Discounted gym rental is available if **80% of the applying team has active full-time student status** at BME in the given semester."
},
"process": {
"title": "Application Process and Deadlines",
"description": "Applications can be submitted via the specified online form. Completed member lists should be sent via email to **bmesport@umsz.bme.hu** by the deadline specified in the call for applications.",
"warning": "**Important!** Incomplete applications or those received after the deadline cannot be accepted."
},
"requiredData": {
"title": "Required Data for Application",
"intro": "When submitting an application, teams must provide:",
"items": [
"Team name, Sport",
"Team leader's name and contact details (responsible for the team within university sports facilities)",
"Team roster, indicating members with active BME student status",
"Which gym(s) the team wishes to use",
"How many times a week the team would train",
"Which days and time slots are suitable for the team",
"The team's top 3 results from the last 2 years (if applicable)"
]
},
"selection": {
"title": "Evaluation and Priority",
"intro": "The applications are assessed by the Sports Division of BME Operating and Technical Service Ltd., with the approval of the EHK. **In case of oversubscription**, the evaluation committee prioritizes teams based on the following criteria:",
"items": [
"Teams containing the highest number of **active BME students**.",
"Teams with **better results** in sports competitions."
],
"warning": "**Important!** There is no possibility to appeal the results of the gym scheduling."
},
"usage": {
"title": "Information on Rental and Usage",
"items": [
"**Gym Scheduling:** The final schedule will be available on the date specified in the announcement. All applicants will be notified via email.",
"**Athletes’ Circle:** Only individuals included on the list submitted during the application process are permitted to play during the assigned time slot. Always carry a photo ID when attending. If an unregistered person is found playing with the team, the team will lose its right to use the facility, and there is no obligation to refund the prepaid rental fee. The roster may be modified slightly during the semester, provided the Sport Division is notified in advance at **bmesport@umsz.bme.hu**.",
"**Footwear:** Access to the sports courts is permitted only in **non-marking sports shoes with light-colored soles**.",
"**House Rules:** Compliance with the facility's House Rules is mandatory.",
"**Dormitory Key Holders:** Teams wishing to use dormitory gyms must designate a maximum of 4 'Key Holders' on their member list. Only these individuals are authorized to pick up keys at the dormitory receptions.",
"**Kármán/Bercsényi Gyms:** The Kármán gym is primarily intended for training-style bookings. It is recommended to schedule matches or match-oriented training sessions in the Bercsényi gym."
]
},
"costs": {
"title": "Rental Fees (For Information Only)",
"description": "BME students can use the sports facilities at a discount. Rental fees must be paid to the Sport Division.",
"items": [
"**Dormitory Gyms:** Different hourly rates for peak and off-peak hours.",
"**BME Sports Center:** Prices may increase in tiers depending on the number of participants."
]
},
"contact": {
"title": "Contact",
"description": "In case of questions: **bmesport@umsz.bme.hu**"
},
"footer": "*Accurate information is always contained in the call for applications published for the specific semester."
}
},

"language_education": {
"title": "Language Education",
"info_box": {
Expand Down
Loading