Skip to content

Conversation

@houssembaltii
Copy link
Contributor

@houssembaltii houssembaltii commented Nov 7, 2025

Summary by CodeRabbit

Release Notes

  • New Features
    • Schedule items now display status badges—"Cancelled" with an X icon and "New" with a sparkle icon—for talks that have been cancelled or replaced.
    • Cancelled talks appear visually distinct with strikethrough text, reduced opacity, and greyscale styling.
    • Cancelled talks are automatically filtered from schedule displays and listings.

✏️ Tip: You can customize this high-level summary in your review settings.

@houssembaltii houssembaltii self-assigned this Nov 7, 2025
@vercel
Copy link

vercel bot commented Nov 7, 2025

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

Project Deployment Preview Comments Updated (UTC)
forkit-community Ready Ready Preview Comment Nov 21, 2025 11:32am

@coderabbitai
Copy link

coderabbitai bot commented Nov 7, 2025

Walkthrough

The changes introduce a status field to schedule items to mark talks as "cancelled" or "replacement", update the UI component to display visual indicators, and add filtering logic across the codebase to exclude cancelled talks from various processing pipelines.

Changes

Cohort / File(s) Summary
Schema Definition
src/schemas/events.ts
Added status enum field to schedule items with options ["cancelled", "replacement", "published"] and default value "published".
Component Display
src/components/Schedule/CardConference.astro
Updated card to look up schedule item status; apply strikethrough and reduced opacity for cancelled talks; display "Cancelled" badge with FiXCircle icon and "New" badge with IoSparklesSharp for replacements; apply grayscale filter to speakers grid and language badge container when cancelled.
Filtering Logic
src/lib/events.ts,
src/pages/events/[id].html.md/index.ts,
src/pages/events/[id]/assets/_utils.ts
Added filtering to skip cancelled talks during speaker prefetch, schedule display rendering, and asset source generation by checking schedule item status against "cancelled".
Event Content
src/content/events/2025-malaysia-kuala-lumpur/index.mdx
Marked one conference talk at 11:00 as cancelled and added a replacement talk with identical start time and duration.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

  • File spread & heterogeneity: Changes span schema definitions, component rendering, business logic filtering, and content data—requiring separate reasoning for each concern.
  • Filtering pattern repetition: Similar filtering logic applied across three separate files (src/lib/events.ts, src/pages/events/[id].html.md/index.ts, src/pages/events/[id]/assets/_utils.ts) warrants consistency checks.
  • Schema impact: Verify that the new status field default value ("published") is correctly applied and doesn't break existing event data without explicit status values.
  • UI logic: Ensure the cn utility correctly applies conditional styling (opacity, line-through, grayscale) and that both "Cancelled" and "New" badge states are mutually exclusive or properly handled.

Poem

🐰 A conference schedule, once so bright,
Now marks the cancelled with graceful sight—
A strikethrough, grayed, an X so clear,
While replacements sparkle, fresh and dear!
Status fields and filters aligned,
A better talk selection, refined.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main functionality added: informing attendees about schedule updates when a speaker withdraws, which is implemented through new status badges (Cancelled/New) and visual indicators in the CardConference component.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/inform-attendees-about-schedule-update

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dbfcd33 and d868153.

📒 Files selected for processing (5)
  • src/components/Schedule/CardConference.astro (3 hunks)
  • src/content/events/2025-malaysia-kuala-lumpur/index.mdx (1 hunks)
  • src/schemas/events.ts (1 hunks)
  • src/styles/globals.css (1 hunks)
  • tailwind.config.mjs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/components/Schedule/CardConference.astro (1)
src/pages/events/[id].html.md/index.ts (3)
  • item (84-90)
  • event (66-93)
  • item (76-77)
src/schemas/events.ts (3)
src/schemas/forKidsEvent.ts (1)
  • SchemaContext (5-19)
src/schemas/news.ts (1)
  • SchemaContext (4-13)
src/lib/events.ts (1)
  • EventDetails (22-27)
🔇 Additional comments (5)
src/content/events/2025-malaysia-kuala-lumpur/index.mdx (1)

38-43: LGTM! Clear demonstration of the cancellation/replacement feature.

The schedule correctly marks the original talk as cancelled and introduces a replacement at the same time slot, effectively demonstrating the new status-driven UI functionality.

tailwind.config.mjs (1)

20-20: LGTM! Consistent with existing color token pattern.

The success color token follows the same HSL variable pattern as other semantic colors in the theme.

src/schemas/events.ts (1)

150-152: LGTM! Well-structured schema addition.

The status field is properly typed with sensible enum values and includes a default value of "published" to ensure backward compatibility with existing schedule items.

src/components/Schedule/CardConference.astro (2)

66-75: Good implementation of conditional title styling.

The use of the cn utility to conditionally apply line-through styling based on cancellation status provides a clear visual indicator to users.


77-92: Effective visual treatment for cancelled talks.

Applying grayscale to the speakers grid when a talk is cancelled provides appropriate visual feedback while maintaining information visibility.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/events.ts (1)

53-81: Consider filtering cancelled talks when building the talks array.

The current implementation includes cancelled talks in event.data._computed.talks (lines 53-64) but then excludes their speakers when building event.data._computed.speakers (lines 72-76). This creates an inconsistency where cancelled talks exist in the computed data but are filtered out at the display layer.

For better clarity and efficiency:

  1. Filter cancelled talks once when building the talks array
  2. Remove the runtime guard in speaker resolution (lines 72-76)
  3. This aligns with the filtering approach in other files and avoids processing cancelled talks multiple times

Apply this refactor:

 const talks = (
   event.data.schedule
     ? await Promise.all(
         (event.data.schedule?.items ?? []).map(async (item) => {
-          if (!item.slug) {
+          if (!item.slug || item.status === "cancelled") {
             return;
           }
           return await getEntry("talks", item.slug.id);
         }),
       )
     : []
 ).filter((i) => !!i);

 const speakers = (
   await Promise.all(
     talks.flatMap(
       (talk) =>
         talk.data.speakers?.map(async (speaker) => {
           if (!speaker) return;
-          const scheduleTalk = event.data.schedule?.items?.find(
-            (item) => item.slug?.id === talk.id,
-          );
-          const isSpeakerTalkCanceled = scheduleTalk?.status === "cancelled";
-          if (isSpeakerTalkCanceled) return;
           return await getEntry("people", speaker.id.id);
         }) ?? [],
     ),
   )
 ).filter((i) => !!i);
♻️ Duplicate comments (2)
src/components/Schedule/CardConference.astro (2)

32-35: Remove debug console.log and unnecessary await.

Line 35 contains a debug log that should not be committed to production. Line 32 uses await on Array.find(), which returns synchronously and doesn't require await.

Apply this diff:

-const scheduleItem = await (event.data.schedule?.items ?? []).find(
+const scheduleItem = (event.data.schedule?.items ?? []).find(
   (conference) => conference.slug?.id === talk?.id,
 );
-console.log("lena", scheduleItem);

57-64: Clean up redundant and incorrect CSS classes.

Line 58 has several issues:

  • from-accent is used without a gradient utility (should be bg-gradient-to-r to have effect, or removed)
  • text-accent-foreground text-white declares text color twice
  • Lines 60-61 repeat text-white when it's already inherited from the parent container

Apply this diff:

       {scheduleItem?.status === "replacement" && (
-        <div class="h-full w-fit justify-center rounded-full bg-success from-accent px-2 py-1 text-accent-foreground text-white">
+        <div class="h-full w-fit justify-center rounded-full bg-success px-2 py-1 text-white">
           <div class="flex items-center gap-2">
-            <FiPlus className="h-4 w-4 text-white" />
-            <span class="text-sm font-medium text-white">New Talk</span>
+            <FiPlus className="h-4 w-4" />
+            <span class="text-sm font-medium">New Talk</span>
           </div>
         </div>
       )}
🧹 Nitpick comments (1)
src/pages/events/[id].html.md/index.ts (1)

66-99: Consider refactoring to reduce filtering duplication.

The displaySchedule function filters cancelled talks twice—once for the talks array (lines 68-73) and once for itemsWithTime (lines 78-79). Both filters check scheduleTalk?.status !== "cancelled" on the same schedule items, which duplicates logic and makes maintenance harder.

Consider extracting the non-cancelled schedule items once at the beginning of the function:

 const displaySchedule = async (event: EventWithComputed) => {
   if (isEmpty(event.data._computed.talks)) return "";
+  
+  const nonCancelledScheduleItems = event.data.schedule?.items?.filter(
+    (item) => item.status !== "cancelled"
+  ) ?? [];
+  
-  const talks = event.data._computed.talks.filter((talk) => {
-    const scheduleTalk = event.data.schedule?.items?.find(
-      (item) => item.slug?.id === talk.id,
-    );
-    return scheduleTalk?.status !== "cancelled";
-  });
+  const talks = event.data._computed.talks.filter((talk) =>
+    nonCancelledScheduleItems.some((item) => item.slug?.id === talk.id)
+  );
+  
-  const itemsWithTime =
-    event.data.schedule?.items?.filter(
-      (item) =>
-        (item.type === "conference" || item.type === "roundtable") &&
-        item.startTime &&
-        item.status !== "cancelled",
-    ) ?? [];
+  const itemsWithTime = nonCancelledScheduleItems.filter(
+    (item) =>
+      (item.type === "conference" || item.type === "roundtable") &&
+      item.startTime
+  );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d868153 and 9485541.

📒 Files selected for processing (4)
  • src/components/Schedule/CardConference.astro (3 hunks)
  • src/lib/events.ts (1 hunks)
  • src/pages/events/[id].html.md/index.ts (2 hunks)
  • src/pages/events/[id]/assets/_utils.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/lib/events.ts (2)
src/pages/events/[id]/talks/[talkId]/assets/_utils.ts (2)
  • speaker (12-27)
  • talkId (4-30)
src/schemas/talks.ts (1)
  • z (5-28)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/components/Schedule/CardConference.astro (1)

63-70: Clean up redundant and incorrect CSS classes.

The "New" badge contains several CSS issues previously flagged:

  • from-accent is used without a gradient utility (should be bg-gradient-to-r or removed)
  • text-accent-foreground text-white declares text color twice
  • Lines 66-67 repeat text-white when already inherited from parent
  • justify-center has no effect (parent div is not a flex container; only the child div on line 65 is)

Apply this diff to clean up the classes:

-        <div class="isolate h-full w-fit justify-center rounded-full bg-success from-accent px-2 py-1 text-accent-foreground text-white">
+        <div class="h-full w-fit rounded-full bg-success px-2 py-1 text-white">
           <div class="flex items-center gap-1">
-            <IoSparklesSharp className="h-4 w-4 text-white" />
-            <span class="text-sm font-medium text-white">New</span>
+            <IoSparklesSharp className="h-4 w-4" />
+            <span class="text-sm font-medium">New</span>
           </div>
         </div>
🧹 Nitpick comments (1)
src/components/Schedule/CardConference.astro (1)

55-70: Consider adding screen reader text for status badges.

The "Cancelled" and "New" badges are visual-only. Screen reader users won't be informed that a talk has been cancelled or is a replacement, which impacts accessibility.

Consider adding visually hidden text or aria-labels:

       {scheduleItem?.status === "cancelled" && (
         <div class="h-full w-fit rounded-full bg-gradient-to-r from-destructive to-destructive/80 px-2 py-1 text-destructive-foreground">
           <div class="flex items-center gap-1">
             <FiXCircle className="h-4 w-4" />
-            <span class="text-sm font-medium">Cancelled</span>
+            <span class="text-sm font-medium" aria-label="This talk has been cancelled">Cancelled</span>
           </div>
         </div>
       )}
       {scheduleItem?.status === "replacement" && (
         <div class="h-full w-fit rounded-full bg-success px-2 py-1 text-white">
           <div class="flex items-center gap-1">
             <IoSparklesSharp className="h-4 w-4" />
-            <span class="text-sm font-medium">New</span>
+            <span class="text-sm font-medium" aria-label="This is a new replacement talk">New</span>
           </div>
         </div>
       )}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 302f85a and 4add3f4.

📒 Files selected for processing (1)
  • src/components/Schedule/CardConference.astro (4 hunks)
🔇 Additional comments (4)
src/components/Schedule/CardConference.astro (4)

3-3: LGTM! Icon imports support the new status badges.

The sparkles icon (IoSparklesSharp) for the "New" badge addresses the previous user feedback about the plus icon being confusing. The imports are appropriate for the status-aware UI.

Also applies to: 8-9


32-34: LGTM! Past review feedback addressed.

The unnecessary await and debug console.log have been removed as requested in the previous review.


74-88: LGTM! Conditional styling for cancelled talks.

The speakers grid correctly applies grayscale styling when a talk is cancelled, providing appropriate visual feedback to users.


90-106: LGTM! Layered grayscale styling for status awareness.

The conditional grayscale on the container combined with the existing grayscale on the badges creates a layered visual effect that appropriately mutes cancelled talks.

@JeanneGrenet
Copy link
Collaborator

Nice for the icon
Be careful, you have conflicts on your PR

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/pages/events/[id].html.md/index.ts (1)

68-100: Potential index mismatch between filtered talks and time labels.

The code assumes a 1:1 correspondence between the talks array (lines 70-75) and itemsWithTime (lines 76-82), but they're filtered independently:

  • talks filters event.data._computed.talks by finding corresponding schedule items with status !== "cancelled"
  • itemsWithTime filters event.data.schedule?.items by type, startTime presence, and status !== "cancelled"

If the schedule contains items without slugs, or if the ordering differs between computed talks and schedule items, formattedItems[index] on line 93 could reference the wrong time or go out of bounds.

Consider matching each talk to its corresponding schedule item for time lookup:

 const displaySchedule = async (event: EventWithComputed) => {
   if (isEmpty(event.data._computed.talks)) return "";
   const talks = event.data._computed.talks.filter((talk) => {
     const scheduleTalk = event.data.schedule?.items?.find(
       (item) => item.slug?.id === talk.id,
     );
     return scheduleTalk?.status !== "cancelled";
   });
-  const itemsWithTime =
-    event.data.schedule?.items?.filter(
-      (item) =>
-        (item.type === "conference" || item.type === "roundtable") &&
-        item.startTime &&
-        item.status !== "cancelled",
-    ) ?? [];
-
-  const formattedItems = itemsWithTime.map((item) =>
-    dayjs(item.startTime).format("hh:mmA"),
-  );

   return `## Schedule

 ${(
   await Promise.all(
-    talks.map(async (item, index) => {
-      const timeStart = formattedItems[index];
+    talks.map(async (item) => {
+      const scheduleItem = event.data.schedule?.items?.find(
+        (schedItem) => schedItem.slug?.id === item.id,
+      );
+      const timeStart = scheduleItem?.startTime 
+        ? dayjs(scheduleItem.startTime).format("hh:mmA")
+        : "TBD";
       return `- [${item.data.title}](${lunalink(
         ROUTES.events[":id"].talks[":talkId"].__path,
         { id: event.id, talkId: item.id },
       )}): ${timeStart} by ${(await Promise.all(item.data.speakers.map(async (speaker) => (await getEntry(speaker.id)).data.name))).join(", ")}`;
     }),
   )
 ).join("\n")}`;
 };
♻️ Duplicate comments (1)
src/components/Schedule/CardConference.astro (1)

63-70: Clean up redundant CSS classes on the "New" badge.

Line 64 contains several redundant or incorrect classes that were flagged in a previous review but not fully addressed:

  • from-accent has no effect without a gradient utility like bg-gradient-to-r
  • text-accent-foreground text-white declares text color twice
  • isolate is unclear in purpose here
  • Lines 66-67 repeat text-white when it should inherit from the parent

Apply this diff to clean up the classes:

       {scheduleItem?.status === "replacement" && (
-        <div class="isolate h-full w-fit justify-center rounded-full bg-success from-accent px-2 py-1 text-accent-foreground text-white">
+        <div class="h-full w-fit justify-center rounded-full bg-success px-2 py-1 text-white">
           <div class="flex items-center gap-1">
-            <FiPlus className="h-4 w-4 text-white" />
-            <span class="text-sm font-medium text-white">New</span>
+            <FiPlus className="h-4 w-4" />
+            <span class="text-sm font-medium">New</span>
           </div>
         </div>
       )}

Based on past review comments that weren't fully addressed.

🧹 Nitpick comments (1)
src/lib/events.ts (1)

72-78: Consider optimizing the schedule item lookup for better performance.

The current implementation searches event.data.schedule?.items for each speaker, resulting in O(n×m) complexity. For events with many talks and speakers, this could impact performance.

Consider building a lookup map before the speaker processing:

+  const scheduleItemMap = new Map(
+    (event.data.schedule?.items ?? [])
+      .filter((item) => item.slug)
+      .map((item) => [item.slug!.id, item])
+  );
+
   const speakers = (
     await Promise.all(
       talks.flatMap(
         (talk) =>
           talk.data.speakers?.map(async (speaker) => {
             if (!speaker) return;
-            const scheduleTalk = event.data.schedule?.items?.find(
-              (item) => item.slug?.id === talk.id,
-            );
-            const isSpeakerTalkCanceled = scheduleTalk?.status === "cancelled";
+            const scheduleTalk = scheduleItemMap.get(talk.id);
+            const isSpeakerTalkCanceled = scheduleTalk?.status === "cancelled";
             if (isSpeakerTalkCanceled) {
               return;
             }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4add3f4 and 0467e23.

📒 Files selected for processing (8)
  • src/components/Schedule/CardConference.astro (4 hunks)
  • src/content/events/2025-malaysia-kuala-lumpur/index.mdx (1 hunks)
  • src/lib/events.ts (1 hunks)
  • src/pages/events/[id].html.md/index.ts (2 hunks)
  • src/pages/events/[id]/assets/_utils.ts (1 hunks)
  • src/schemas/events.ts (1 hunks)
  • src/styles/globals.css (1 hunks)
  • tailwind.config.mjs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/pages/events/[id]/assets/_utils.ts
  • src/styles/globals.css
  • tailwind.config.mjs
  • src/content/events/2025-malaysia-kuala-lumpur/index.mdx
🧰 Additional context used
🧬 Code graph analysis (2)
src/schemas/events.ts (1)
src/schemas/news.ts (1)
  • SchemaContext (4-13)
src/lib/events.ts (2)
src/pages/events/[id]/talks/[talkId]/assets/_utils.ts (2)
  • talkId (4-30)
  • speaker (12-27)
src/pages/events/[id]/talks/[talkId]/assets/_square.tsx (1)
  • speaker (36-46)
🔇 Additional comments (3)
src/schemas/events.ts (1)

155-157: LGTM! Schema change is well-designed.

The addition of the status enum field to schedule items is correctly implemented with:

  • Clear semantic values ("cancelled", "replacement", "published")
  • Sensible default value ("published") ensuring backward compatibility
  • Proper integration with the existing schedule item structure
src/components/Schedule/CardConference.astro (2)

32-34: LGTM! Schedule item lookup is correct.

The synchronous lookup correctly matches the talk to its schedule item, and the previous issue with unnecessary await has been addressed.


73-106: LGTM! Conditional styling for cancelled talks is well-implemented.

The grayscale effects applied to speakers and language badges when talks are cancelled provide clear visual feedback. The conditional logic using cn() is clean and consistent.

@yoannfleurydev
Copy link
Member

New render

image

@yoannfleurydev yoannfleurydev merged commit ade40e5 into main Nov 21, 2025
2 of 3 checks passed
@yoannfleurydev yoannfleurydev deleted the feat/inform-attendees-about-schedule-update branch November 21, 2025 11:32
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.

✨ Inform attendees about cancelled talks at events

4 participants