Skip to content

feat: implement redesigned dormitories overview page with CMS integra…#170

Open
DankaMarci wants to merge 1 commit into
mainfrom
130-implement-redesigned-dormitories-overview-kollégiumok-bemutatója-page-cms-integration

Hidden character warning

The head ref may contain hidden characters: "130-implement-redesigned-dormitories-overview-koll\u00e9giumok-bemutat\u00f3ja-page-cms-integration"
Open

feat: implement redesigned dormitories overview page with CMS integra…#170
DankaMarci wants to merge 1 commit into
mainfrom
130-implement-redesigned-dormitories-overview-kollégiumok-bemutatója-page-cms-integration

Conversation

@DankaMarci

@DankaMarci DankaMarci commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

…tion

Summary by CodeRabbit

  • New Features

    • Added a dormitory overview page with image tiles, localized titles, and links to either external pages or internal detail pages.
    • Introduced dormitory content support so new dormitory entries can be managed and displayed in the app.
  • Bug Fixes

    • Added a fallback display when no dormitory cards are available.
    • Improved card rendering so images, details, and empty states appear correctly in both English and Hungarian.

@DankaMarci DankaMarci requested a review from peterlipt July 3, 2026 12:27
@DankaMarci DankaMarci self-assigned this Jul 3, 2026
@vercel

vercel Bot commented Jul 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ehk Ready Ready Preview, Comment Jul 3, 2026 12:28pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new Dormitories Payload CMS collection with a database migration and generated types, a getDormitories() data-fetching helper, a rewritten ImageCard component, and a reworked dormitory-overview page that fetches and renders dormitory cards with a fallback list, alongside updated Hungarian/English dictionary strings.

Changes

Dormitories Feature

Layer / File(s) Summary
Collection, migration, and config wiring
src/collections/Dormitories.ts, src/migrations/20260703_140815_dormitories_collection.ts, src/migrations/index.ts, src/payload.config.ts, src/payload-types.ts
Adds the Dormitories collection with URL validation and field definitions, a migration creating the dormitories table and relations, registration in payload.config.ts, and generated Dormitory/DormitoriesSelect types.
Dormitories fetch helper
src/lib/payload-cms.ts
Adds getDormitories() which queries the dormitories collection sorted by order and returns typed docs.
ImageCard component rewrite
src/components/common/ImageCard.tsx
Rebuilds ImageCard with an article-based layout, next/image fill, ArrowRight icon, optional detailsLabel/description, and conditional external anchor vs internal Link routing.
Overview page and localization
src/app/(app)/[lang]/kollegium/kollegium-bemutato/page.tsx, src/dictionaries/en/dormitories.json, src/dictionaries/hu/dormitories.json
Converts the page to force-dynamic, concurrently fetches dictionary and dormitory data, maps records to ImageCard data with a static fallback list, renders a grid or localized no-results message, and updates dictionary strings for introduction, details, and no_results.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Page as DormitoriesOverviewPage
  participant Dict as getDictionary
  participant CMS as getDormitories
  participant ImageCard

  Page->>Dict: getDictionary(lang, "dormitories")
  Page->>CMS: getDormitories()
  CMS-->>Page: Dormitory[]
  Dict-->>Page: dictionary
  Page->>Page: map dormitories to cards (or fallbackDormitories)
  Page->>ImageCard: render cards with title, href, imageSrc, detailsLabel
Loading

Suggested reviewers: peterlipt

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: a redesigned dormitories overview page with CMS integration.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 130-implement-redesigned-dormitories-overview-kollégiumok-bemutatója-page-cms-integration

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@peterlipt

Copy link
Copy Markdown
Member

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
src/migrations/20260703_140815_dormitories_collection.ts (1)

9-9: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Same NOT NULL vs. ON DELETE SET NULL conflict as flagged in Dormitories.ts.

cover_image_id is NOT NULL (Line 9) but the FK constraint (Line 17) is ON DELETE set null, which will fail with a constraint violation the first time a referenced Media doc is deleted. See detailed comment on src/collections/Dormitories.ts (coverImage field) for the root cause and suggested fixes.

Also applies to: 17-17

🤖 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/migrations/20260703_140815_dormitories_collection.ts` at line 9, The
migration for the dormitories collection has the same nullability mismatch as
the Dormitories collection definition: cover_image_id is declared NOT NULL while
the foreign key uses ON DELETE SET NULL. Update the schema in this migration so
the column nullability matches the FK behavior, or change the FK action to match
the non-null constraint; use the cover_image_id column and its FK constraint in
the dormitories migration as the reference points.
🧹 Nitpick comments (1)
src/collections/Dormitories.ts (1)

38-47: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add slug format validation.

slug has no format constraint, yet it's interpolated directly into route paths downstream (/${lang}/kollegium/kollegium-bemutato/${dormitory.slug}). An admin entering spaces, slashes, or other special characters would produce broken/unexpected URLs.

♻️ Suggested validation
     {
       name: "slug",
       label: "Slug",
       type: "text",
       required: true,
       unique: true,
       admin: {
         description: "Útvonalhoz használt azonosító, pl. baross, sch.",
       },
+      validate: (val: string | null | undefined) => {
+        if (!val) return "A slug megadása kötelező.";
+        return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(val)
+          ? true
+          : "A slug csak kisbetűket, számokat és kötőjeleket tartalmazhat.";
+      },
     },
🤖 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/Dormitories.ts` around lines 38 - 47, Add format validation
for the slug field in Dormitories so only URL-safe values are accepted. Update
the slug field definition in the Dormitories collection to enforce a slug-style
pattern (for example lowercase letters, numbers, and hyphens only), and keep it
aligned with how dormitory.slug is later interpolated into route paths. Use the
existing slug field configuration in Dormitories as the place to add the
validation so invalid values with spaces, slashes, or special characters are
rejected before save.
🤖 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]/kollegium/kollegium-bemutato/page.tsx:
- Around line 80-111: The empty-state branch in page.tsx is unreachable because
renderedCards always falls back to fallbackDormitories, so d.no_results can
never render. Update the logic around renderedCards and the conditional render
in the kollegium-bemutato page so the empty state is driven by the actual CMS
result (cards.length) or otherwise avoid using the always-nonempty fallback when
deciding whether to show the no_results paragraph.

In `@src/collections/Dormitories.ts`:
- Around line 48-54: The coverImage field in Dormitories is configured as
required while the underlying cover_image_id foreign key uses a delete behavior
that sets null, so adjust one side to match. Update the Dormitories collection
definition around coverImage by either removing required: true so the relation
can be nullable, or change the FK delete action for cover_image_id to
restrict/delete instead of set null. Make sure the chosen behavior is consistent
with the coverImage field and any related media deletion logic.

In `@src/components/common/ImageCard.tsx`:
- Around line 30-38: The ImageCard component uses next/image with a remote media
URL from the Payload S3-backed collection, but the app config does not whitelist
that host. Update the Next.js image configuration in next.config.ts to add the
media origin via images.remotePatterns or images.domains, and make sure the
Image usage in ImageCard still renders remote coverImage.url sources correctly.

---

Duplicate comments:
In `@src/migrations/20260703_140815_dormitories_collection.ts`:
- Line 9: The migration for the dormitories collection has the same nullability
mismatch as the Dormitories collection definition: cover_image_id is declared
NOT NULL while the foreign key uses ON DELETE SET NULL. Update the schema in
this migration so the column nullability matches the FK behavior, or change the
FK action to match the non-null constraint; use the cover_image_id column and
its FK constraint in the dormitories migration as the reference points.

---

Nitpick comments:
In `@src/collections/Dormitories.ts`:
- Around line 38-47: Add format validation for the slug field in Dormitories so
only URL-safe values are accepted. Update the slug field definition in the
Dormitories collection to enforce a slug-style pattern (for example lowercase
letters, numbers, and hyphens only), and keep it aligned with how dormitory.slug
is later interpolated into route paths. Use the existing slug field
configuration in Dormitories as the place to add the validation so invalid
values with spaces, slashes, or special characters are rejected before save.
🪄 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: c7d49b82-6654-4b07-aaa8-de9449821126

📥 Commits

Reviewing files that changed from the base of the PR and between 2cbebd5 and 2b10680.

📒 Files selected for processing (10)
  • src/app/(app)/[lang]/kollegium/kollegium-bemutato/page.tsx
  • src/collections/Dormitories.ts
  • src/components/common/ImageCard.tsx
  • src/dictionaries/en/dormitories.json
  • src/dictionaries/hu/dormitories.json
  • src/lib/payload-cms.ts
  • src/migrations/20260703_140815_dormitories_collection.ts
  • src/migrations/index.ts
  • src/payload-types.ts
  • src/payload.config.ts

Comment on lines +80 to +111
const renderedCards =
cards.length > 0
? cards
: fallbackDormitories.map((dormitory) => ({
...dormitory,
href: `/${lang}/kollegium/kollegium-bemutato/${dormitory.slug}`,
}));

return (
<div className="min-h-screen bg-gray-50">
<div className="min-h-screen bg-[#f9f4f0]">
<div className="container mx-auto px-2 md:px-4 py-8">
<PageHeader title={dictionary.dormitories.admission_information.introduction} />
<DormitoryCardsContainer dormitory={dictionary.dormitories.admission_information.dormitory} linkOrRoute="route"/>
<PageHeader title={d.introduction} />
<div className="rounded-b-2xl border-x border-b border-[#e9e2d6] bg-[#fffefc] p-6 md:p-8">
{renderedCards.length > 0 ? (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-3">
{renderedCards.map((dormitory) => (
<ImageCard
key={dormitory.slug}
content={{
href: dormitory.href,
imageSrc: dormitory.imageSrc,
title: dormitory.name,
detailsLabel: d.details,
}}
/>
))}
</div>
) : (
<p className="font-open-sans text-sm leading-[1.6] text-[#6e6660]">
{d.no_results}
</p>
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

d.no_results empty-state is unreachable dead code.

Because fallbackDormitories always has 7 entries, renderedCards is guaranteed non-empty whenever cards is empty. The renderedCards.length > 0 check on Line 93 is therefore always true, and the localized no_results paragraph (Lines 107-111) can never render. Either the fallback defeats the intent of the no_results message, or the empty state should key off cards.length (the actual CMS result) instead of renderedCards.

🤖 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]/kollegium/kollegium-bemutato/page.tsx around lines 80 -
111, The empty-state branch in page.tsx is unreachable because renderedCards
always falls back to fallbackDormitories, so d.no_results can never render.
Update the logic around renderedCards and the conditional render in the
kollegium-bemutato page so the empty state is driven by the actual CMS result
(cards.length) or otherwise avoid using the always-nonempty fallback when
deciding whether to show the no_results paragraph.

Comment on lines +48 to +54
{
name: "coverImage",
label: "Borítókép",
type: "upload",
relationTo: "media",
required: true,
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does Payload CMS postgres adapter always generate ON DELETE SET NULL for required upload/relationship fields regardless of the required flag?

💡 Result:

No, the Payload CMS Postgres adapter does not unconditionally generate ON DELETE SET NULL for all required relationship fields. The behavior of foreign key constraints in Payload's Postgres adapter has been a subject of ongoing development and is not uniform across all scenarios. Historically, Payload has faced challenges managing database integrity when dealing with required relationships and deletions, leading to various issues where users encounter foreign key constraint violations [1][2][3]. The system does not natively implement automatic cascading deletes for all relationship types, and in many cases, attempting to delete a document that is referenced by a required relationship in another record will result in a database error rather than a soft deletion or nullification [1][3]. Key points regarding this behavior include: 1. Relationship Constraints: There is no global configuration that forces ON DELETE SET NULL. In fact, developers have reported that deleting a document often triggers database-level constraint violations because the foreign key is still active [1][3]. 2. Evolution of Fixes: Payload has introduced specific fixes for certain scenarios, such as adding ON DELETE CASCADE to specific internal table relationships (e.g., select hasMany relationships) to prevent these crashes [4][5]. 3. GraphQL and Nullability: In some contexts, Payload has implemented changes—such as forcing nullability for relationship fields in schema generation—to avoid GraphQL errors when a related document is deleted, which can lead to a conflict between the database schema and the application's strict requirement checks [6]. 4. Recommended Approach: Because there is no simple "required field = automatic set null" behavior, managing deletions that involve required relationships typically requires custom implementation, such as using Payload hooks to manually clean up or cascade delete related records before the primary document is deleted [7][3]. In summary, the adapter does not automatically handle required relationships via ON DELETE SET NULL. Users should expect that deleting a document with active required references may fail with a database error unless handled explicitly through logic in the application layer [1][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Files ==\n'
git ls-files 'src/collections/Dormitories.ts' 'src/migrations/20260703_140815_dormitories_collection.ts'

printf '\n== Dormitories collection outline ==\n'
ast-grep outline src/collections/Dormitories.ts --view expanded || true

printf '\n== Migration outline ==\n'
ast-grep outline src/migrations/20260703_140815_dormitories_collection.ts --view expanded || true

printf '\n== Relevant snippets ==\n'
sed -n '1,140p' src/collections/Dormitories.ts | cat -n
printf '\n--- migration ---\n'
sed -n '1,140p' src/migrations/20260703_140815_dormitories_collection.ts | cat -n

Repository: kir-dev/ehk

Length of output: 5459


🏁 Script executed:

#!/bin/bash
set -euo pipefail
git ls-files 'src/collections/Dormitories.ts' 'src/migrations/20260703_140815_dormitories_collection.ts'

Repository: kir-dev/ehk

Length of output: 237


Make coverImage nullable or change the FK delete action. cover_image_id is NOT NULL, so ON DELETE SET NULL will fail when a referenced media row is deleted. Either drop required: true or block media deletion while it’s still referenced.

🤖 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/Dormitories.ts` around lines 48 - 54, The coverImage field in
Dormitories is configured as required while the underlying cover_image_id
foreign key uses a delete behavior that sets null, so adjust one side to match.
Update the Dormitories collection definition around coverImage by either
removing required: true so the relation can be nullable, or change the FK delete
action for cover_image_id to restrict/delete instead of set null. Make sure the
chosen behavior is consistent with the coverImage field and any related media
deletion logic.

Comment on lines +30 to +38
<div className="relative z-10 mx-4 aspect-[349/296] overflow-hidden rounded-2xl border border-[#e9e2d6] bg-[#f9f4f0] sm:mx-8">
<Image
src={imageSrc}
alt={title}
fill
sizes="(max-width: 640px) calc(100vw - 64px), (max-width: 1024px) 45vw, 349px"
className="object-cover transition-transform duration-300 group-hover:scale-105"
/>
</div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect Next.js image config for remotePatterns/domains
fd -H -t f 'next.config.*' --exec cat -n {}

Repository: kir-dev/ehk

Length of output: 627


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== ImageCard =="
fd -H -t f 'ImageCard.tsx' src --exec sh -c 'echo "--- {}"; cat -n "{}"' \;

echo
echo "== overview / imageSrc usage =="
rg -n --context 3 "coverImage|imageSrc|next/image|Image\(" src

echo
echo "== next config / image config references =="
rg -n --context 3 "images:|remotePatterns|domains|withPayload\\(" next.config.* src package.json

echo
echo "== payload config media references =="
rg -n --context 3 "upload|media|s3|cloudinary|url" src/payload.config.ts src

Repository: kir-dev/ehk

Length of output: 50368


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== src/components/common/ImageCard.tsx =="
cat -n src/components/common/ImageCard.tsx

echo
echo "== imageSrc / coverImage usage =="
rg -n --context 2 "coverImage\\.url|imageSrc|ImageCard|<Image " src/components src/app src/lib src

echo
echo "== next.config.* =="
cat -n next.config.ts next.config.mjs next.config.js 2>/dev/null || true

echo
echo "== media/url references near payload config =="
rg -n --context 2 "images:|upload|url:|s3|cloudinary|remotePatterns|domains" src/payload.config.ts src

Repository: kir-dev/ehk

Length of output: 50367


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== src/payload.config.ts (storage/plugins area) =="
sed -n '1,180p' src/payload.config.ts | cat -n

echo
echo "== media collection =="
fd -H -t f 'media*' src --exec sh -c 'echo "--- {}"; sed -n "1,220p" "{}" | cat -n' \;

echo
echo "== withPayload / image config docs in repo =="
rg -n --context 2 "remotePatterns|domains|images\\s*:|withPayload\\(" .

Repository: kir-dev/ehk

Length of output: 5564


Whitelist the media origin for next/image

coverImage.url comes from Payload’s S3-backed media collection, but next.config.ts doesn’t define any images.remotePatterns or images.domains. If a dormitory card resolves to a remote S3 URL, this <Image> will fail at runtime. Add the media host to images.remotePatterns (or render these sources unoptimized).

🤖 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/components/common/ImageCard.tsx` around lines 30 - 38, The ImageCard
component uses next/image with a remote media URL from the Payload S3-backed
collection, but the app config does not whitelist that host. Update the Next.js
image configuration in next.config.ts to add the media origin via
images.remotePatterns or images.domains, and make sure the Image usage in
ImageCard still renders remote coverImage.url sources correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Redesigned Dormitories Overview (Kollégiumok bemutatója) Page & CMS Integration

2 participants