121 implement redesigned academic scholarship tanulmányi ösztöndíj page and cms integration#159
Hidden character warning
Conversation
- Updated RepresentativeCard component to enhance accessibility and visual design. - Refactored RepresentativeModal to streamline layout and improve user experience. - Modified RepresentativesGrid to accept title and description props for better context. - Enhanced RepresentativesGridClient with a back button and improved loading states. - Created a new helpers file for common representative functions and styles. - Improved loading skeletons for representative cards and grid. - Updated page structure in RepresentativesPage for better layout and responsiveness.
… table - Created a new migration to add `representative_id` and `contact_email` columns to the `news` table. - Added foreign key constraint for `representative_id` referencing the `representatives` table. - Created an index on `representative_id` for improved query performance. - Updated the payload types to include optional `representative` and `contactEmail` fields in the News interface.
…rnal link - Created a new migration to add columns for submission process in Hungarian and English, and an external link to the permissions table. - Updated the migrations index to include the new migration. - Extended the Permission interface in payload-types.ts to include types for the new submission process fields and external link.
…th improved styling and structure
…nt structure and styling
- Created migration for academic scholarship FAQ with accordion items. - Updated migrations index to include the new academic scholarship FAQ migration. - Defined AcademicScholarshipFaq and AcademicScholarshipFaqSelect interfaces in payload-types. - Configured global settings to include AcademicScholarshipFAQ in payload configuration.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis PR extends the Payload CMS schema with an ChangesFull-stack feature additions and UI redesign
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
src/app/(app)/[lang]/hirek/[slug]/components/NewsDetailMain.tsx (1)
29-38: ⚡ Quick winExtract duplicated date formatting into a shared helper.
This formatter is duplicated in
NewsDetailMain.tsxandRelatedNewsClient.tsx; centralizing it avoids locale/date drift.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/`(app)/[lang]/hirek/[slug]/components/NewsDetailMain.tsx around lines 29 - 38, The formatDate function in NewsDetailMain.tsx is duplicated in RelatedNewsClient.tsx. Create a shared utility helper file (e.g., in a utils or helpers directory) and move the formatDate function there, ensuring it accepts both the dateString and lang parameters. Then update both NewsDetailMain.tsx and RelatedNewsClient.tsx to import and use this shared formatDate helper instead of maintaining duplicate implementations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app/`(app)/[lang]/hirek/[slug]/components/NewsDetailMain.tsx:
- Around line 46-49: The onClick handler in the button element that calls
router.back() lacks a proper fallback route, and the hardcoded fallback to
/{lang}/hirek is invalid since that page doesn't exist in the routing structure.
To fix this, implement a fallback mechanism by either: (1) accepting a
parentRoute prop in the NewsDetailMain component and using it as the fallback
destination when router.back() fails, (2) using useSearchParams() to capture and
preserve referrer information from the parent route during navigation, or (3)
gracefully handling the case where no valid parent route is available by
redirecting to a valid fallback like the homepage or a category index. The
onClick handler should check window.history.length to determine if back
navigation is safe, and use the configured fallback route instead of the invalid
/{lang}/hirek path.
In `@src/app/`(app)/[lang]/hirek/[slug]/components/RelatedNewsClient.tsx:
- Around line 61-63: The Link component's href attribute is missing the locale
prefix which causes unintended locale switching when navigating to related
articles. In the RelatedNewsClient component where the Link element contains
href={`/hirek/${article.id}`}, modify the href to include the locale segment by
using the lang variable obtained from the useTranslate() hook. Update the href
to construct the path as href={`/${lang.toLowerCase()}/hirek/${article.id}`} to
ensure users remain on their current language version when clicking related news
links.
In `@src/app/`(app)/[lang]/kepviselok/components/RepresentativeCard.tsx:
- Around line 27-41: The article element in RepresentativeCard has role="button"
but contains nested interactive email links (lines 86-94), creating conflicting
accessibility semantics. Remove the role="button" attribute from the article
element and refactor the click handling by moving the onClickAction logic to a
wrapper div or restructuring the component so that the card container is not a
button, allowing the nested email links to be the primary interactive elements.
This will resolve the semantic conflict and improve keyboard and screen-reader
accessibility.
In `@src/app/`(app)/[lang]/nyelvoktatas/page.tsx:
- Around line 6-9: The `lang` parameter extracted from `params` in the page
component is being passed directly to getDictionary without validation, which
can cause the page to crash if an unsupported locale is provided since
loaders[locale] would be undefined. Before calling getDictionary(lang,
'language_education'), validate that the lang value is a supported locale and
apply a fallback pattern (consistent with other pages in the application) to
handle cases where an invalid locale is provided. This ensures that
getDictionary receives only valid locales from the loaders object.
In `@src/collections/Permissions.ts`:
- Around line 100-108: The externalLink field in the Permissions collection is
defined with type "text" which allows arbitrary text input without URL
validation. Modify this field definition to add URL validation by either
changing the type to support URL validation or by adding a validate function
that checks if the provided value is a valid URL format before allowing it to be
saved, ensuring only proper URLs can be set for this external link field.
---
Nitpick comments:
In `@src/app/`(app)/[lang]/hirek/[slug]/components/NewsDetailMain.tsx:
- Around line 29-38: The formatDate function in NewsDetailMain.tsx is duplicated
in RelatedNewsClient.tsx. Create a shared utility helper file (e.g., in a utils
or helpers directory) and move the formatDate function there, ensuring it
accepts both the dateString and lang parameters. Then update both
NewsDetailMain.tsx and RelatedNewsClient.tsx to import and use this shared
formatDate helper instead of maintaining duplicate implementations.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a7655705-e0f1-4d8e-9b3a-8887777855fc
📒 Files selected for processing (57)
src/app/(app)/[lang]/engedelyek/components/PermissionsListClient.tsxsrc/app/(app)/[lang]/engedelyek/page.tsxsrc/app/(app)/[lang]/hatarozatok-tara/components/DecisionsArchiveClient.tsxsrc/app/(app)/[lang]/hirek/[slug]/components/BackNav.tsxsrc/app/(app)/[lang]/hirek/[slug]/components/FileIcon.tsxsrc/app/(app)/[lang]/hirek/[slug]/components/NewsDetail.tsxsrc/app/(app)/[lang]/hirek/[slug]/components/NewsDetailClient.tssrc/app/(app)/[lang]/hirek/[slug]/components/NewsDetailMain.tsxsrc/app/(app)/[lang]/hirek/[slug]/components/NewsDetailSidebar.tsxsrc/app/(app)/[lang]/hirek/[slug]/components/RelatedNewsClient.tsxsrc/app/(app)/[lang]/hirek/[slug]/components/ShareButton.tsxsrc/app/(app)/[lang]/hirek/[slug]/lib/news-utils.tssrc/app/(app)/[lang]/kepviselok/components/RepresentativeCard.tsxsrc/app/(app)/[lang]/kepviselok/components/RepresentativeModal.tsxsrc/app/(app)/[lang]/kepviselok/components/RepresentativesGrid.tsxsrc/app/(app)/[lang]/kepviselok/components/RepresentativesGridClient.tsxsrc/app/(app)/[lang]/kepviselok/components/representatives.helpers.tssrc/app/(app)/[lang]/kepviselok/components/skeletons/LoadingRepresentativeCard.tsxsrc/app/(app)/[lang]/kepviselok/components/skeletons/LoadingRepresentativesGrid.tsxsrc/app/(app)/[lang]/kepviselok/page.tsxsrc/app/(app)/[lang]/kisokosok/components/HelpPageList.tsxsrc/app/(app)/[lang]/kisokosok/components/skeletons/LoadingHelpPageGrid.tsxsrc/app/(app)/[lang]/kisokosok/page.tsxsrc/app/(app)/[lang]/nyelvoktatas/components/LanguageEducationContent.tsxsrc/app/(app)/[lang]/nyelvoktatas/page.tsxsrc/app/(app)/[lang]/oktatasi-szabalyzatok/loading.tsxsrc/app/(app)/[lang]/oktatasi-szabalyzatok/page.tsxsrc/app/(app)/[lang]/tanulmanyi-osztondij/components/StudyScholarshipContent.tsxsrc/app/(app)/[lang]/tanulmanyi-osztondij/page.tsxsrc/app/(app)/globals.csssrc/collections/News.tssrc/collections/Permissions.tssrc/components/common/Accordion.tsxsrc/components/common/FileCard.tsxsrc/components/regulations/RegulationsListClient.tsxsrc/components/regulations/skeletons/LoadingRegulationsGrid.tsxsrc/dictionaries/en/language_education.jsonsrc/dictionaries/en/news.jsonsrc/dictionaries/en/permissions.jsonsrc/dictionaries/en/regulations.jsonsrc/dictionaries/en/scholarships.jsonsrc/dictionaries/hu/language_education.jsonsrc/dictionaries/hu/news.jsonsrc/dictionaries/hu/permissions.jsonsrc/dictionaries/hu/regulations.jsonsrc/dictionaries/hu/scholarships.jsonsrc/globals/AcademicScholarshipFAQ.tssrc/lib/payload-cms.tssrc/migrations/20260619_105937_add_news_representative_and_contact_email.jsonsrc/migrations/20260619_105937_add_news_representative_and_contact_email.tssrc/migrations/20260619_141957_add_permissions_submission_and_external_link.jsonsrc/migrations/20260619_141957_add_permissions_submission_and_external_link.tssrc/migrations/20260619_173736_academic_scholarship_faq.jsonsrc/migrations/20260619_173736_academic_scholarship_faq.tssrc/migrations/index.tssrc/payload-types.tssrc/payload.config.ts
💤 Files with no reviewable changes (5)
- src/app/(app)/[lang]/hirek/[slug]/components/BackNav.tsx
- src/app/(app)/[lang]/hirek/[slug]/components/NewsDetailClient.ts
- src/app/(app)/[lang]/hirek/[slug]/components/ShareButton.tsx
- src/app/(app)/[lang]/hirek/[slug]/lib/news-utils.ts
- src/app/(app)/[lang]/hirek/[slug]/components/FileIcon.tsx
| <button | ||
| type="button" | ||
| onClick={() => router.back()} | ||
| className="group inline-flex items-center gap-2 bg-[#862633] hover:bg-[#9e2d3e] text-white border border-[#e9e2d6] rounded-full px-4 py-2 transition-colors duration-200 active:scale-95 cursor-pointer" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify whether other pages using router.back() already implement a fallback.
rg -nP --type=tsx '\brouter\.back\s*\(' src -C3Repository: kir-dev/ehk
Length of output: 83
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Search for router.back usage without tsx type filter
rg -n 'router\.back' src -A 3 -B 3
# Also get the file structure to understand the layout
echo "=== File structure ==="
find src -name "*.tsx" -o -name "*.ts" | head -30Repository: kir-dev/ehk
Length of output: 4802
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the specific file mentioned in the review
cat -n src/app/\(app\)/\[lang\]/hirek/\[slug\]/components/NewsDetailMain.tsx | head -60Repository: kir-dev/ehk
Length of output: 2885
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Search for router usage patterns in hirek-related files
rg -n 'router\.' src -t js -t ts --iglob '*hirek*' -C 2Repository: kir-dev/ehk
Length of output: 37
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find the hirek page to confirm the list route
find src -path "*hirek*" -name "page.tsx" | head -10
cat -n src/app/\(app\)/\[lang\]/hirek/page.tsx 2>/dev/null | head -30Repository: kir-dev/ehk
Length of output: 504
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check RepresentativesGridClient for similar context
cat -n src/app/\(app\)/\[lang\]/kepviselok/components/RepresentativesGridClient.tsx | sed -n '40,65p'Repository: kir-dev/ehk
Length of output: 2170
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check the main hirek page that corresponds to NewsDetailMain
ls -la src/app/\(app\)/\[lang\]/hirek/ 2>/dev/null
cat -n src/app/\(app\)/\[lang\]/hirek/page.tsx 2>/dev/null | head -40Repository: kir-dev/ehk
Length of output: 222
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check PageHeader to see how it handles the fallback
cat -n src/components/common/PageHeader.tsx | head -50Repository: kir-dev/ehk
Length of output: 1658
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check which hirek page imports NewsDetailMain
rg -n "NewsDetailMain" src --type ts --type tsx -B 2 -A 2Repository: kir-dev/ehk
Length of output: 83
🏁 Script executed:
#!/bin/bash
set -euo pipefetch
# Check the news detail slug page to understand the routing context
cat -n src/app/\(app\)/\[lang\]/hirek/\[slug\]/page.tsxRepository: kir-dev/ehk
Length of output: 110
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check which hirek page imports NewsDetailMain
rg -n "NewsDetailMain" src -B 2 -A 2Repository: kir-dev/ehk
Length of output: 2064
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check the news detail slug page to understand the routing context
cat -n "src/app/(app)/[lang]/hirek/[slug]/page.tsx"Repository: kir-dev/ehk
Length of output: 1178
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check if there's ANY hirek page at the root level
find src/app -name "*hirek*" -type dRepository: kir-dev/ehk
Length of output: 407
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check the routing structure - are there any pages that list news?
rg -n "export.*function.*News" src --type ts -A 5 | head -50Repository: kir-dev/ehk
Length of output: 3296
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check what the actual news list route is - look at all hirek pages
for f in src/app/*/\[lang\]/*/hirek/page.tsx src/app/\(app\)/\[lang\]/*/hirek/page.tsx; do
if [ -f "$f" ]; then
echo "=== $f ==="
head -20 "$f"
fi
doneRepository: kir-dev/ehk
Length of output: 19445
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check if there's a main hirek page (not a category-specific one)
ls -la "src/app/(app)/[lang]/hirek/"
cat -n "src/app/(app)/[lang]/hirek/page.tsx" 2>/dev/null || echo "No main hirek page found"Repository: kir-dev/ehk
Length of output: 247
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check how NewsDetailMain is instantiated - does it receive any props about parent route?
cat -n "src/app/(app)/[lang]/hirek/[slug]/components/NewsDetail.tsx"Repository: kir-dev/ehk
Length of output: 1345
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check if there's referrer detection or any context management
rg -n "useSearchParams\|usePathname\|referrer" src/app/\(app\)/\[lang\]/hirek -A 2 -B 2Repository: kir-dev/ehk
Length of output: 37
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify: does the news detail page have a way to know its source/category?
# Check what params are available in the slug page
cat -n "src/app/(app)/[lang]/hirek/[slug]/page.tsx" | tail -20
# Also check if there's any navigation/breadcrumb info passed
rg -n "searchParams\|params" "src/app/(app)/[lang]/hirek/[slug]/page.tsx" -A 2Repository: kir-dev/ehk
Length of output: 665
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check if router.back() is used anywhere with a fallback pattern
rg -n "window.history" src -A 3 -B 3Repository: kir-dev/ehk
Length of output: 37
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Understand the real concern: can users direct-enter news pages?
# Check if there are any navigation links TO the detail pages
rg -n "hirek.*slug\|hirek.*\[slug\]" src --type ts -B 2 -A 2 | head -40Repository: kir-dev/ehk
Length of output: 37
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Let's understand: can we detect what category/section we came from?
# Check how news articles are linked from category pages
rg -n "Link.*hirek\|href.*hirek.*slug" src --type ts -B 2 -A 2 | head -60Repository: kir-dev/ehk
Length of output: 37
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify if there are ANY valid fallback routes for news
find src/app -path "*hirek*" -name "page.tsx" -exec grep -l "NewsGrid\|News" {} \;Repository: kir-dev/ehk
Length of output: 504
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Most importantly: check if window.history.length is actually a reliable method in Next.js
# and what best practices recommend for fallback navigation
rg -n "history.length\|history.back" srcRepository: kir-dev/ehk
Length of output: 37
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify the actual routing structure - what's the proper parent route for news?
# Check if there are any breadcrumbs or navigation structure that hints at parent
rg -n "breadcrumb\|Breadcrumb\|parent" src/app/\(app\)/\[lang\]/hirek -iRepository: kir-dev/ehk
Length of output: 37
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check how news is actually discoverable - what's the entry point?
# Look for navigation menus or site structure
rg -n "hirek" src/components/common -i -B 1 -A 1 | head -30Repository: kir-dev/ehk
Length of output: 37
Back button fallback route is incorrect and will cause 404 errors.
Line 48 uses router.back() without a fallback, which can fail for direct entries. However, the proposed fallback to /{lang}/hirek is invalid—that page doesn't exist in the routing structure. The news detail page at /[lang]/hirek/[slug] is generic and doesn't know which category the article came from (kollegium, sport, etc.).
A viable fix requires either:
- Passing the parent route as a prop to
NewsDetailMain - Using
useSearchParams()to preserve referrer information - Handling the case where no valid parent route exists (redirect to homepage or category index)
The window.history.length approach is sound, but the destination route must be valid or configurable.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/`(app)/[lang]/hirek/[slug]/components/NewsDetailMain.tsx around lines
46 - 49, The onClick handler in the button element that calls router.back()
lacks a proper fallback route, and the hardcoded fallback to /{lang}/hirek is
invalid since that page doesn't exist in the routing structure. To fix this,
implement a fallback mechanism by either: (1) accepting a parentRoute prop in
the NewsDetailMain component and using it as the fallback destination when
router.back() fails, (2) using useSearchParams() to capture and preserve
referrer information from the parent route during navigation, or (3) gracefully
handling the case where no valid parent route is available by redirecting to a
valid fallback like the homepage or a category index. The onClick handler should
check window.history.length to determine if back navigation is safe, and use the
configured fallback route instead of the invalid /{lang}/hirek path.
| <Link | ||
| href={`/hirek/${article.id}`} | ||
| className="inline-flex items-center justify-between gap-4 text-xs font-bold text-[#862633]" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Confirm route shape for news detail pages
fd -a "page.tsx" src/app | rg "/hirek/"
# 2) Inspect how `slug` param is read in news detail page(s)
rg -nP --type=tsx "params.*slug|\\[slug\\]" src/app -C2
# 3) Compare all generated hrefs targeting /hirek/*
rg -nP --type=tsx 'href=\{`/hirek/\$\{[^}]+\}`\}|href="\/hirek\/' src -C2Repository: kir-dev/ehk
Length of output: 740
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Read the RelatedNewsClient component around the flagged lines
echo "=== RelatedNewsClient.tsx context (lines 50-70) ==="
sed -n '50,70p' src/app/\(app\)/\[lang\]/hirek/\[slug\]/components/RelatedNewsClient.tsx
# 2) Read the slug/page.tsx to understand how slug is used
echo -e "\n=== [slug]/page.tsx content ==="
cat src/app/\(app\)/\[lang\]/hirek/\[slug\]/page.tsx
# 3) Check for middleware or i18n setup
echo -e "\n=== Middleware files ==="
find src -name "middleware.*" -o -name "*i18n*" -o -name "*locale*" | head -20
# 4) Search for other /hirek/ hrefs to see pattern
echo -e "\n=== Other /hirek/ href patterns ==="
rg 'href.*hirek' src/app --type ts --type tsx -B2 -A2 2>/dev/null | head -50Repository: kir-dev/ehk
Length of output: 1909
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Read middleware to understand lang prefix handling
echo "=== middleware.ts ==="
cat src/middleware.ts
# 2) Read i18n-config to understand locale setup
echo -e "\n=== i18n-config.ts ==="
cat src/i18n-config.ts
# 3) Check the full RelatedNewsClient component for type info
echo -e "\n=== RelatedNewsClient.tsx full file ==="
cat src/app/\(app\)/\[lang\]/hirek/\[slug\]/components/RelatedNewsClient.tsx
# 4) Look for other news/article links with href patterns
echo -e "\n=== Search for other article/news hrefs ==="
rg 'href.*article|href.*news' src/app -A1 2>/dev/null | head -60Repository: kir-dev/ehk
Length of output: 5112
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Verify useTranslate hook to confirm lang variable format
echo "=== useTranslate hook implementation ==="
find src -name "*useTranslate*" -type f
xargs cat 2>/dev/null | head -40
# 2) Verify lang variable case in RelatedNewsClient (is it 'EN'/'HU' or 'en'/'hu'?)
echo -e "\n=== Check i18n context/context for lang format ==="
rg "defaultLang|Lang" src/components/common/LanguageProvider.tsx -A3 -B3Repository: kir-dev/ehk
Length of output: 2650
Fix missing locale segment in related news link to prevent unintended locale switching.
The href on line 62 omits the locale prefix: href={/hirek/${article.id}} should be href={/${lang.toLowerCase()}/hirek/${article.id}}.
When a user navigates from a localized page (e.g., /en/hirek/456) to a related article without a locale segment, the middleware auto-prepends the default locale (hu), causing the user to be redirected to /hu/hirek/... instead of /en/hirek/.... This unintentionally switches the user's language preference.
The lang variable is already available in the component via the useTranslate() hook; use it to construct the correct localized path.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/`(app)/[lang]/hirek/[slug]/components/RelatedNewsClient.tsx around
lines 61 - 63, The Link component's href attribute is missing the locale prefix
which causes unintended locale switching when navigating to related articles. In
the RelatedNewsClient component where the Link element contains
href={`/hirek/${article.id}`}, modify the href to include the locale segment by
using the lang variable obtained from the useTranslate() hook. Update the href
to construct the path as href={`/${lang.toLowerCase()}/hirek/${article.id}`} to
ensure users remain on their current language version when clicking related news
links.
| <article | ||
| role="button" | ||
| tabIndex={0} | ||
| onClick={onClickAction} | ||
| onKeyDown={(event) => { | ||
| // Ignore key events bubbling up from nested interactive elements (e.g. the email link) | ||
| if (event.target !== event.currentTarget) return | ||
| if (event.key === "Enter" || event.key === " ") { | ||
| event.preventDefault() | ||
| onClickAction() | ||
| } | ||
| }} | ||
| className="group relative min-h-[31.6rem] cursor-pointer pt-16 focus-visible:outline-none" | ||
| aria-label={`${detailsLabel}: ${representative.name}`} | ||
| > |
There was a problem hiding this comment.
Avoid nested interactive semantics in the card container.
Line 28 makes the whole <article> a button role, but Lines 86-94 include nested email links. This creates conflicting interaction semantics and is an accessibility blocker for keyboard/screen-reader users.
Proposed fix
- <article
- role="button"
- tabIndex={0}
- onClick={onClickAction}
- onKeyDown={(event) => {
- // Ignore key events bubbling up from nested interactive elements (e.g. the email link)
- if (event.target !== event.currentTarget) return
- if (event.key === "Enter" || event.key === " ") {
- event.preventDefault()
- onClickAction()
- }
- }}
- className="group relative min-h-[31.6rem] cursor-pointer pt-16 focus-visible:outline-none"
- aria-label={`${detailsLabel}: ${representative.name}`}
- >
+ <article
+ onClick={onClickAction}
+ className="group relative min-h-[31.6rem] cursor-pointer pt-16"
+ >
@@
- <div className="w-full border-t border-[`#e9e2d6`] pt-4">
- <div className="flex h-[22px] items-center justify-between gap-4 font-open-sans text-sm font-semibold leading-[1.6] text-[`#862633`]">
+ <div className="w-full border-t border-[`#e9e2d6`] pt-4">
+ <button
+ type="button"
+ onClick={(event) => {
+ event.stopPropagation()
+ onClickAction()
+ }}
+ aria-label={`${detailsLabel}: ${representative.name}`}
+ className="flex h-[22px] w-full items-center justify-between gap-4 font-open-sans text-sm font-semibold leading-[1.6] text-[`#862633`] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[`#862633`] focus-visible:ring-offset-2"
+ >
<span>{detailsLabel}</span>
<ArrowRight className="h-6 w-6 shrink-0 transition-transform duration-200 group-hover:translate-x-1 group-focus-visible:translate-x-1" />
- </div>
+ </button>
</div>Also applies to: 83-95, 100-104
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/`(app)/[lang]/kepviselok/components/RepresentativeCard.tsx around
lines 27 - 41, The article element in RepresentativeCard has role="button" but
contains nested interactive email links (lines 86-94), creating conflicting
accessibility semantics. Remove the role="button" attribute from the article
element and refactor the click handling by moving the onClickAction logic to a
wrapper div or restructuring the component so that the card container is not a
button, allowing the nested email links to be the primary interactive elements.
This will resolve the semantic conflict and improve keyboard and screen-reader
accessibility.
| params }: { params: Promise<{ lang: Locale }> }) { | ||
| const { lang } = await params; | ||
| const dictionary = await getDictionary(lang, 'language_education'); | ||
|
|
There was a problem hiding this comment.
Validate route locale before dictionary lookup
At Line 8, getDictionary(lang, 'language_education') uses raw route params. An unsupported locale can crash the page (loaders[locale] is undefined). Align with the fallback pattern used in other pages.
Suggested fix
import LanguageEducationContent from "`@/app/`(app)/[lang]/nyelvoktatas/components/LanguageEducationContent";
import { getDictionary } from "`@/get-dictionary`";
-import { Locale } from "`@/i18n-config`";
+import { i18n, Locale } from "`@/i18n-config`";
export default async function LanguageEducationPage({
- params }: { params: Promise<{ lang: Locale }> }) {
+ params }: { params: Promise<{ lang: string }> }) {
const { lang } = await params;
- const dictionary = await getDictionary(lang, 'language_education');
+ const validLang = i18n.locales.includes(lang as Locale) ? (lang as Locale) : i18n.defaultLocale;
+ const dictionary = await getDictionary(validLang, "language_education");🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/`(app)/[lang]/nyelvoktatas/page.tsx around lines 6 - 9, The `lang`
parameter extracted from `params` in the page component is being passed directly
to getDictionary without validation, which can cause the page to crash if an
unsupported locale is provided since loaders[locale] would be undefined. Before
calling getDictionary(lang, 'language_education'), validate that the lang value
is a supported locale and apply a fallback pattern (consistent with other pages
in the application) to handle cases where an invalid locale is provided. This
ensures that getDictionary receives only valid locales from the loaders object.
| { | ||
| name: "externalLink", | ||
| type: "text", | ||
| required: false, | ||
| label: "Külső link (űrlap URL)", | ||
| admin: { | ||
| description: "Külső webes űrlaphoz tartozó URL (pl. \"Rendezvénybejelentő űrlap\"). Ha meg van adva, a kártya ezt nyitja meg fájl helyett.", | ||
| }, | ||
| }, |
There was a problem hiding this comment.
Validate externalLink as a URL, not arbitrary text.
Line 102 defines a URL-intended field as plain text without validation. This allows invalid or unsafe values to reach the UI click target and can break navigation behavior.
Suggested schema hardening
{
name: "externalLink",
- type: "text",
+ type: "text",
required: false,
label: "Külső link (űrlap URL)",
+ validate: (value: unknown) => {
+ if (value == null || value === "") return true;
+ if (typeof value !== "string") return "Érvénytelen URL.";
+ try {
+ const url = new URL(value);
+ if (!["http:", "https:"].includes(url.protocol)) {
+ return "Csak http/https URL engedélyezett.";
+ }
+ return true;
+ } catch {
+ return "Érvénytelen URL.";
+ }
+ },
admin: {
description: "Külső webes űrlaphoz tartozó URL (pl. \"Rendezvénybejelentő űrlap\"). Ha meg van adva, a kártya ezt nyitja meg fájl helyett.",
},
},🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/collections/Permissions.ts` around lines 100 - 108, The externalLink
field in the Permissions collection is defined with type "text" which allows
arbitrary text input without URL validation. Modify this field definition to add
URL validation by either changing the type to support URL validation or by
adding a validate function that checks if the provided value is a valid URL
format before allowing it to be saved, ensuring only proper URLs can be set for
this external link field.
Summary by CodeRabbit
New Features
Bug Fixes & Improvements