From 9a9b6247079886682f1366f27fedf3fb21c1159b Mon Sep 17 00:00:00 2001 From: Dmitry Romanenko Date: Fri, 20 Mar 2026 17:23:09 -0400 Subject: [PATCH 1/3] Glow watched items in calendar as green --- .../app/components/common/entity-display.tsx | 18 ++++++++---- .../app/components/media/display-items.tsx | 2 ++ .../app/routes/_dashboard.calendar.tsx | 29 +++++++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/apps/frontend/app/components/common/entity-display.tsx b/apps/frontend/app/components/common/entity-display.tsx index 203296dcbc..069ffc1224 100644 --- a/apps/frontend/app/components/common/entity-display.tsx +++ b/apps/frontend/app/components/common/entity-display.tsx @@ -273,6 +273,7 @@ type BaseEntityDisplayItemCard = { centerElement?: ReactNode; isDetailsLoading: boolean; wasRecentlyConsumed?: boolean; + isCalendarEventWatched?: boolean; isPartialStatusActive?: boolean; consumeButtonIndicatorLabel?: string; userToMediaReasons?: UserToMediaReason[]; @@ -305,6 +306,7 @@ const BaseEntityDisplayItemComponent = forwardRef< const alreadyInWatchlist = alreadyInCollectionNames.includes("Watchlist"); const shouldHighlightImage = coreDetails.isServerKeyValidated && props.wasRecentlyConsumed; + const isCalendarEventWatched = props.isCalendarEventWatched; const progress = useMemo(() => { if (props.progress === undefined || props.progress === null) @@ -328,13 +330,17 @@ const BaseEntityDisplayItemComponent = forwardRef< () => ({ overflow: "hidden", transition: "box-shadow 200ms ease", - boxShadow: shouldHighlightImage + boxShadow: isCalendarEventWatched ? mode === "dark" - ? "0px 0px 4px 1px rgba(242, 183, 22, 1)" - : "0px 0px 8px 3px rgba(24, 142, 245, 1)" - : undefined, + ? "0px 0px 4px 1px rgba(64, 192, 87, 1)" + : "0px 0px 8px 3px rgba(47, 158, 68, 1)" + : shouldHighlightImage + ? mode === "dark" + ? "0px 0px 4px 1px rgba(242, 183, 22, 1)" + : "0px 0px 8px 3px rgba(24, 142, 245, 1)" + : undefined, }), - [mode, shouldHighlightImage], + [mode, shouldHighlightImage, isCalendarEventWatched], ); const gradientBackgroundStyle = useMemo( () => ({ @@ -432,7 +438,7 @@ const BaseEntityDisplayItemComponent = forwardRef< style={cardStyle} ref={viewportRef} className={props.imageClassName} - withBorder={!shouldHighlightImage} + withBorder={!shouldHighlightImage && !isCalendarEventWatched} > {props.centerElement ? ( <> diff --git a/apps/frontend/app/components/media/display-items.tsx b/apps/frontend/app/components/media/display-items.tsx index ef3039f6e7..6d5dbfef31 100644 --- a/apps/frontend/app/components/media/display-items.tsx +++ b/apps/frontend/app/components/media/display-items.tsx @@ -30,6 +30,7 @@ export const MetadataDisplayItem = (props: { imageClassName?: string; centerElement?: ReactNode; additionalInformation?: string; + isCalendarEventWatched?: boolean; shouldHighlightNameIfInteracted?: boolean; onImageClickBehavior?: () => Promise; }) => { @@ -114,6 +115,7 @@ export const MetadataDisplayItem = (props: { imageClassName={props.imageClassName} isDetailsLoading={isMetadataDetailsLoading} wasRecentlyConsumed={isMetadataRecentlyConsumed} + isCalendarEventWatched={props.isCalendarEventWatched} isPartialStatusActive={isMetadataPartialStatusActive} image={metadataImageTranslation || images.at(0)} title={metadataTitleTranslation || metadataDetails?.title} diff --git a/apps/frontend/app/routes/_dashboard.calendar.tsx b/apps/frontend/app/routes/_dashboard.calendar.tsx index 860381775a..806c46605b 100644 --- a/apps/frontend/app/routes/_dashboard.calendar.tsx +++ b/apps/frontend/app/routes/_dashboard.calendar.tsx @@ -24,6 +24,7 @@ import { ApplicationGrid } from "~/components/common/layout"; import { MetadataDisplayItem } from "~/components/media/display-items"; import { useFiltersState } from "~/lib/hooks/filters/use-state"; import { dayjsLib } from "~/lib/shared/date-utils"; +import { useUserMetadataDetails } from "~/lib/shared/hooks"; import { clientGqlService, queryFactory } from "~/lib/shared/react-query"; const defaultFiltersState = { @@ -109,6 +110,10 @@ type CalendarDate = UserCalendarEventsQuery["userCalendarEvents"][number]; const CalendarEventMetadata = (props: { item: CalendarDate["events"][number]; }) => { + const { data: userMetadataDetails } = useUserMetadataDetails( + props.item.metadataId, + ); + const additionalInformation = useMemo(() => { if (props.item.showExtraInformation) return `Upcoming: S${props.item.showExtraInformation?.season}-E${props.item.showExtraInformation?.episode}`; @@ -116,10 +121,34 @@ const CalendarEventMetadata = (props: { return `Upcoming: EP-${props.item.podcastExtraInformation?.episode}`; }, [props.item]); + const isCalendarEventWatched = useMemo(() => { + if (!userMetadataDetails) return false; + const showInfo = props.item.showExtraInformation; + if (showInfo) { + const seasonProgress = userMetadataDetails.showProgress?.find( + (s) => s.seasonNumber === showInfo.season, + ); + if (!seasonProgress) return false; + const episodeProgress = seasonProgress.episodes.find( + (e) => e.episodeNumber === showInfo.episode, + ); + return (episodeProgress?.timesSeen ?? 0) > 0; + } + const podcastInfo = props.item.podcastExtraInformation; + if (podcastInfo) { + const episodeProgress = userMetadataDetails.podcastProgress?.find( + (e) => e.episodeNumber === podcastInfo.episode, + ); + return (episodeProgress?.timesSeen ?? 0) > 0; + } + return false; + }, [userMetadataDetails, props.item]); + return ( ); }; From 1e6ce9364939e834d0e47b4ff1b40f81bef302ea Mon Sep 17 00:00:00 2001 From: Dmitry Romanenko Date: Fri, 20 Mar 2026 17:42:05 -0400 Subject: [PATCH 2/3] Rabbit review corrections --- .../app/components/common/entity-display.tsx | 7 ++--- .../app/components/media/display-items.tsx | 28 +++++++++++++++-- .../app/routes/_dashboard.calendar.tsx | 31 ++----------------- 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/apps/frontend/app/components/common/entity-display.tsx b/apps/frontend/app/components/common/entity-display.tsx index 069ffc1224..0396a7ed11 100644 --- a/apps/frontend/app/components/common/entity-display.tsx +++ b/apps/frontend/app/components/common/entity-display.tsx @@ -306,7 +306,6 @@ const BaseEntityDisplayItemComponent = forwardRef< const alreadyInWatchlist = alreadyInCollectionNames.includes("Watchlist"); const shouldHighlightImage = coreDetails.isServerKeyValidated && props.wasRecentlyConsumed; - const isCalendarEventWatched = props.isCalendarEventWatched; const progress = useMemo(() => { if (props.progress === undefined || props.progress === null) @@ -330,7 +329,7 @@ const BaseEntityDisplayItemComponent = forwardRef< () => ({ overflow: "hidden", transition: "box-shadow 200ms ease", - boxShadow: isCalendarEventWatched + boxShadow: props.isCalendarEventWatched ? mode === "dark" ? "0px 0px 4px 1px rgba(64, 192, 87, 1)" : "0px 0px 8px 3px rgba(47, 158, 68, 1)" @@ -340,7 +339,7 @@ const BaseEntityDisplayItemComponent = forwardRef< : "0px 0px 8px 3px rgba(24, 142, 245, 1)" : undefined, }), - [mode, shouldHighlightImage, isCalendarEventWatched], + [mode, shouldHighlightImage, props.isCalendarEventWatched], ); const gradientBackgroundStyle = useMemo( () => ({ @@ -438,7 +437,7 @@ const BaseEntityDisplayItemComponent = forwardRef< style={cardStyle} ref={viewportRef} className={props.imageClassName} - withBorder={!shouldHighlightImage && !isCalendarEventWatched} + withBorder={!shouldHighlightImage && !props.isCalendarEventWatched} > {props.centerElement ? ( <> diff --git a/apps/frontend/app/components/media/display-items.tsx b/apps/frontend/app/components/media/display-items.tsx index 6d5dbfef31..4c899d916c 100644 --- a/apps/frontend/app/components/media/display-items.tsx +++ b/apps/frontend/app/components/media/display-items.tsx @@ -4,6 +4,8 @@ import { EntityTranslationVariant, MediaLot, SeenState, + type SeenShowExtraInformationPartFragment, + type SeenPodcastExtraInformationPartFragment, UserToMediaReason, } from "@ryot/generated/graphql/backend/graphql"; import { changeCase, snakeCase } from "@ryot/ts-utils"; @@ -30,7 +32,8 @@ export const MetadataDisplayItem = (props: { imageClassName?: string; centerElement?: ReactNode; additionalInformation?: string; - isCalendarEventWatched?: boolean; + calendarEventShowInfo?: SeenShowExtraInformationPartFragment; + calendarEventPodcastInfo?: SeenPodcastExtraInformationPartFragment; shouldHighlightNameIfInteracted?: boolean; onImageClickBehavior?: () => Promise; }) => { @@ -73,6 +76,27 @@ export const MetadataDisplayItem = (props: { [UserToMediaReason.Finished, UserToMediaReason.Owned].includes(r), ); + const isCalendarEventWatched = useMemo(() => { + if (!userMetadataDetails) return false; + if (props.calendarEventShowInfo) { + const seasonProgress = userMetadataDetails.showProgress?.find( + (s) => s.seasonNumber === props.calendarEventShowInfo?.season, + ); + if (!seasonProgress) return false; + const episodeProgress = seasonProgress.episodes.find( + (e) => e.episodeNumber === props.calendarEventShowInfo?.episode, + ); + return (episodeProgress?.timesSeen ?? 0) > 0; + } + if (props.calendarEventPodcastInfo) { + const episodeProgress = userMetadataDetails.podcastProgress?.find( + (e) => e.episodeNumber === props.calendarEventPodcastInfo?.episode, + ); + return (episodeProgress?.timesSeen ?? 0) > 0; + } + return false; + }, [userMetadataDetails, props.calendarEventShowInfo, props.calendarEventPodcastInfo]); + const extraInformation = useMemo(() => { if (!metadataDetails || !userMetadataDetails) return ""; @@ -115,7 +139,7 @@ export const MetadataDisplayItem = (props: { imageClassName={props.imageClassName} isDetailsLoading={isMetadataDetailsLoading} wasRecentlyConsumed={isMetadataRecentlyConsumed} - isCalendarEventWatched={props.isCalendarEventWatched} + isCalendarEventWatched={isCalendarEventWatched} isPartialStatusActive={isMetadataPartialStatusActive} image={metadataImageTranslation || images.at(0)} title={metadataTitleTranslation || metadataDetails?.title} diff --git a/apps/frontend/app/routes/_dashboard.calendar.tsx b/apps/frontend/app/routes/_dashboard.calendar.tsx index 806c46605b..43c232e52e 100644 --- a/apps/frontend/app/routes/_dashboard.calendar.tsx +++ b/apps/frontend/app/routes/_dashboard.calendar.tsx @@ -24,7 +24,6 @@ import { ApplicationGrid } from "~/components/common/layout"; import { MetadataDisplayItem } from "~/components/media/display-items"; import { useFiltersState } from "~/lib/hooks/filters/use-state"; import { dayjsLib } from "~/lib/shared/date-utils"; -import { useUserMetadataDetails } from "~/lib/shared/hooks"; import { clientGqlService, queryFactory } from "~/lib/shared/react-query"; const defaultFiltersState = { @@ -110,10 +109,6 @@ type CalendarDate = UserCalendarEventsQuery["userCalendarEvents"][number]; const CalendarEventMetadata = (props: { item: CalendarDate["events"][number]; }) => { - const { data: userMetadataDetails } = useUserMetadataDetails( - props.item.metadataId, - ); - const additionalInformation = useMemo(() => { if (props.item.showExtraInformation) return `Upcoming: S${props.item.showExtraInformation?.season}-E${props.item.showExtraInformation?.episode}`; @@ -121,34 +116,12 @@ const CalendarEventMetadata = (props: { return `Upcoming: EP-${props.item.podcastExtraInformation?.episode}`; }, [props.item]); - const isCalendarEventWatched = useMemo(() => { - if (!userMetadataDetails) return false; - const showInfo = props.item.showExtraInformation; - if (showInfo) { - const seasonProgress = userMetadataDetails.showProgress?.find( - (s) => s.seasonNumber === showInfo.season, - ); - if (!seasonProgress) return false; - const episodeProgress = seasonProgress.episodes.find( - (e) => e.episodeNumber === showInfo.episode, - ); - return (episodeProgress?.timesSeen ?? 0) > 0; - } - const podcastInfo = props.item.podcastExtraInformation; - if (podcastInfo) { - const episodeProgress = userMetadataDetails.podcastProgress?.find( - (e) => e.episodeNumber === podcastInfo.episode, - ); - return (episodeProgress?.timesSeen ?? 0) > 0; - } - return false; - }, [userMetadataDetails, props.item]); - return ( ); }; From c03f84709e5946cc2df422aeb4e0635adedd18f0 Mon Sep 17 00:00:00 2001 From: Diptesh Choudhuri Date: Sat, 21 Mar 2026 08:17:23 +0530 Subject: [PATCH 3/3] fix: reorder calendar event properties in MetadataDisplayItem --- .../app/components/common/entity-display.tsx | 2 +- apps/frontend/app/components/media/display-items.tsx | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/frontend/app/components/common/entity-display.tsx b/apps/frontend/app/components/common/entity-display.tsx index 0396a7ed11..a708f9feec 100644 --- a/apps/frontend/app/components/common/entity-display.tsx +++ b/apps/frontend/app/components/common/entity-display.tsx @@ -273,8 +273,8 @@ type BaseEntityDisplayItemCard = { centerElement?: ReactNode; isDetailsLoading: boolean; wasRecentlyConsumed?: boolean; - isCalendarEventWatched?: boolean; isPartialStatusActive?: boolean; + isCalendarEventWatched?: boolean; consumeButtonIndicatorLabel?: string; userToMediaReasons?: UserToMediaReason[]; onImageClickBehavior: [string, (() => Promise)?]; diff --git a/apps/frontend/app/components/media/display-items.tsx b/apps/frontend/app/components/media/display-items.tsx index 4c899d916c..2ceddb0243 100644 --- a/apps/frontend/app/components/media/display-items.tsx +++ b/apps/frontend/app/components/media/display-items.tsx @@ -32,10 +32,10 @@ export const MetadataDisplayItem = (props: { imageClassName?: string; centerElement?: ReactNode; additionalInformation?: string; - calendarEventShowInfo?: SeenShowExtraInformationPartFragment; - calendarEventPodcastInfo?: SeenPodcastExtraInformationPartFragment; shouldHighlightNameIfInteracted?: boolean; onImageClickBehavior?: () => Promise; + calendarEventShowInfo?: SeenShowExtraInformationPartFragment; + calendarEventPodcastInfo?: SeenPodcastExtraInformationPartFragment; }) => { const { ref, inViewport } = useInViewport(); @@ -95,7 +95,11 @@ export const MetadataDisplayItem = (props: { return (episodeProgress?.timesSeen ?? 0) > 0; } return false; - }, [userMetadataDetails, props.calendarEventShowInfo, props.calendarEventPodcastInfo]); + }, [ + userMetadataDetails, + props.calendarEventShowInfo, + props.calendarEventPodcastInfo, + ]); const extraInformation = useMemo(() => { if (!metadataDetails || !userMetadataDetails) return ""; @@ -138,8 +142,8 @@ export const MetadataDisplayItem = (props: { centerElement={props.centerElement} imageClassName={props.imageClassName} isDetailsLoading={isMetadataDetailsLoading} - wasRecentlyConsumed={isMetadataRecentlyConsumed} isCalendarEventWatched={isCalendarEventWatched} + wasRecentlyConsumed={isMetadataRecentlyConsumed} isPartialStatusActive={isMetadataPartialStatusActive} image={metadataImageTranslation || images.at(0)} title={metadataTitleTranslation || metadataDetails?.title}