Repository: IgnisDa/ryot (language: rust)

Issue:
[Feature Request] - Display media progress inline
Making this ticket based on some discussion on Discord.

Somewhat related to #996, looking to track progress of items in ryot similar to how services like [Hardcover](https://hardcover.app) and [AniList](https://anilist.co) do it:

![image](https://github.com/user-attachments/assets/9d845908-5a34-4f01-ac30-c6e99f598d68)

![image](https://github.com/user-attachments/assets/10b2eaf8-9445-49d7-8b56-c1651205776c)

This would essentially involve adding a new metadata field for all items where you can specify progress towards some total amount (in units of pages, episodes, minutes/hours, etc.) and then have the progress percentage dynamically calculated and displayed under items on a dedicated page and/or in the usual grid views.

My initial suggestion would be to do something similar to how a special backpack icon shows up for items in the "owned" collection in the grid view. Maybe add progress (as a percentage or fraction or something) to one of the corners:

![image](https://github.com/user-attachments/assets/4f1c0969-401a-49b9-940b-49d81b995834)

See [this comment](https://github.com/IgnisDa/ryot/issues/996#issuecomment-2395292558) for another potential option. Basically, a progress bar underneath the item in the grid view.


Discussion / hints:
> you can specify progress towards some total amount (in units of pages, episodes, minutes/hours, etc.) 

Why do you need to specify total amount? Most media already have that.
> > you can specify progress towards some total amount (in units of pages, episodes, minutes/hours, etc.)
> 
> Why do you need to specify total amount? Most media already have that.

True, but sometimes the total amount specified in the database doesn't quite match the version you have. For example, maybe you're reading an ebook where the number of pages changes based on font size, zoom level, screen resolution, etc. It would be nice to be able to manually override the value retrieved from the database.
Fair enough. I can provide this value on the seen record level. Would that be fine?
If by "seen record level" you mean the Update Progress button under Actions, that should work and I think that makes the most sense from a UX perspective.

![image](https://github.com/user-attachments/assets/92b22ef5-af0c-47b6-b50a-ca90f15aa0b1)

Additionally, I did want to call out one detail that was slightly annoying about the way Hardcover handled progress for audio books. It asks you to specify progress towards the total, but providers like Spotify only show you progress *remaining* (see below):

![image](https://github.com/user-attachments/assets/fce82ab9-29a1-41ca-a35b-02dcb4f9fbf9)

This required a little bit of mental math every time I wanted to update the record to subtract the remaining time from the total time. If possible, it would be nice to specify **either** completed progress or remaining progress and have the record automatically calculate the completed progress.
For this issue, i will like to just tackle the displaying progress part. For the other part about updating progress (time remaining thing and custom total), please create a separate issue and we can display it there.

Fix patch:
diff --git a/apps/frontend/app/components/common.tsx b/apps/frontend/app/components/common.tsx
index 3a1c6c6255..32d0e909a1 100644
--- a/apps/frontend/app/components/common.tsx
+++ b/apps/frontend/app/components/common.tsx
@@ -8,16 +8,19 @@ import {
 	Badge,
 	Box,
 	Button,
+	Center,
 	Checkbox,
 	Collapse,
 	Divider,
 	Flex,
 	Group,
 	Image,
+	type MantineStyleProp,
 	Modal,
 	MultiSelect,
 	Paper,
 	SimpleGrid,
+	Skeleton,
 	Stack,
 	Text,
 	TextInput,
@@ -47,7 +50,13 @@ import {
 	type ReviewItem,
 	UserReviewScale,
 } from "@ryot/generated/graphql/backend/graphql";
-import { changeCase, getInitials, isNumber, snakeCase } from "@ryot/ts-utils";
+import {
+	changeCase,
+	getInitials,
+	isNumber,
+	isString,
+	snakeCase,
+} from "@ryot/ts-utils";
 import {
 	IconArrowBigUp,
 	IconCheck,
@@ -64,7 +73,7 @@ import {
 } from "@tabler/icons-react";
 import { useMutation, useQuery } from "@tanstack/react-query";
 import Cookies from "js-cookie";
-import type { ReactNode } from "react";
+import type { ReactNode, Ref } from "react";
 import { useState } from "react";
 import { $path } from "remix-routes";
 import type { DeepPartial } from "ts-essentials";
@@ -312,6 +321,157 @@ export const ProRequiredAlert = (props: { tooltipLabel?: string }) => {
 	) : null;
 };
 
+const blackBgStyles = {
+	backgroundColor: "rgba(0, 0, 0, 0.75)",
+	borderRadius: 3,
+	padding: 2,
+} satisfies MantineStyleProp;
+
+export const BaseMediaDisplayItem = (props: {
+	name?: string;
+	altName?: string;
+	progress?: string;
+	isLoading: boolean;
+	nameRight?: ReactNode;
+	imageUrl?: string | null;
+	innerRef?: Ref<HTMLDivElement>;
+	labels?: { right?: ReactNode; left?: ReactNode };
+	onImageClickBehavior: string | (() => Promise<void>);
+	imageOverlay?: {
+		topRight?: ReactNode;
+		topLeft?: ReactNode;
+		bottomRight?: ReactNode;
+		bottomLeft?: ReactNode;
+	};
+}) => {
+	const userPreferences = useUserPreferences();
+	const gridPacking = userPreferences.general.gridPacking;
+	const SurroundingElement = (iProps: { children: ReactNode }) =>
+		isString(props.onImageClickBehavior) ? (
+			<Anchor component={Link} to={props.onImageClickBehavior}>
+				{iProps.children}
+			</Anchor>
+		) : (
+			<Box onClick={props.onImageClickBehavior}>{iProps.children}</Box>
+		);
+	const defaultOverlayProps = {
+		style: { zIndex: 10, ...blackBgStyles },
+		pos: "absolute",
+	} as const;
+
+	return (
+		<Flex justify="space-between" direction="column" ref={props.innerRef}>
+			<Box pos="relative" w="100%">
+				<SurroundingElement>
+					<Tooltip label={props.name} position="top">
+						<Paper style={{ overflow: "hidden" }} pos="relative" radius="md">
+							<Image
+								src={props.imageUrl}
+								style={{
+									cursor: "pointer",
+									...match(gridPacking)
+										.with(GridPacking.Normal, () => ({ height: 260 }))
+										.with(GridPacking.Dense, () => ({ height: 180 }))
+										.exhaustive(),
+								}}
+								alt={`Image for ${props.name}`}
+								className={classes.mediaImage}
+								styles={{
+									root: {
+										transitionProperty: "transform",
+										transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
+										transitionDuration: "150ms",
+									},
+								}}
+								fallbackSrc={useFallbackImageUrl(
+									props.isLoading
+										? "Loading..."
+										: props.name
+											? getInitials(props.name)
+											: undefined,
+								)}
+							/>
+							{props.progress ? (
+								<Paper
+									h={5}
+									bg="red"
+									left={0}
+									bottom={0}
+									pos="absolute"
+									w={`${props.progress}%`}
+								/>
+							) : null}
+						</Paper>
+					</Tooltip>
+				</SurroundingElement>
+				{props.imageOverlay?.topLeft ? (
+					<Center top={5} left={5} {...defaultOverlayProps}>
+						{props.imageOverlay.topLeft}
+					</Center>
+				) : null}
+				{props.imageOverlay?.topRight ? (
+					<Center top={5} right={5} {...defaultOverlayProps}>
+						{props.imageOverlay.topRight}
+					</Center>
+				) : null}
+				{props.imageOverlay?.bottomLeft ? (
+					<Center
+						left={5}
+						bottom={props.progress ? 8 : 5}
+						{...defaultOverlayProps}
+					>
+						{props.imageOverlay.bottomLeft}
+					</Center>
+				) : null}
+				{props.imageOverlay?.bottomRight ? (
+					<Center
+						right={5}
+						bottom={props.progress ? 8 : 5}
+						{...defaultOverlayProps}
+					>
+						{props.imageOverlay.bottomRight}
+					</Center>
+				) : null}
+			</Box>
+			{props.isLoading ? (
+				<>
+					<Skeleton height={22} mt={10} />
+					<Skeleton height={22} mt={8} />
+				</>
+			) : (
+				<Flex
+					w="100%"
+					direction="column"
+					mt={2}
+					px={match(gridPacking)
+						.with(GridPacking.Normal, () => ({ base: 6, md: 3 }))
+						.with(GridPacking.Dense, () => ({ md: 2 }))
+						.exhaustive()}
+				>
+					<Flex w="100%" direction="row" justify="space-between">
+						<Text
+							size="sm"
+							c="dimmed"
+							visibleFrom={gridPacking === GridPacking.Dense ? "md" : undefined}
+						>
+							{props.labels?.left}
+						</Text>
+						<Text c="dimmed" size="sm">
+							{props.labels?.right}
+						</Text>
+					</Flex>
+					<Flex mb="xs" align="center" justify="space-between">
+						<Text w="100%" truncate fw="bold">
+							{props.altName ?? props.name}
+						</Text>
+						{props.nameRight}
+					</Flex>
+				</Flex>
+			)}
+		</Flex>
+	);
+};
+
 export const FiltersModal = (props: {
 	opened: boolean;
 	cookieName: string;
diff --git a/apps/frontend/app/components/fitness.tsx b/apps/frontend/app/components/fitness.tsx
index d44a14ad65..13b52af02c 100644
--- a/apps/frontend/app/components/fitness.tsx
+++ b/apps/frontend/app/components/fitness.tsx
@@ -44,6 +44,7 @@ import type { ComponentType, ReactNode } from "react";
 import { $path } from "remix-routes";
 import { match } from "ts-pattern";
 import { withFragment } from "ufo";
+import { BaseMediaDisplayItem } from "~/components/common";
 import { FitnessEntity, dayjsLib, getSetColor } from "~/lib/generals";
 import { useGetRandomMantineColor, useUserUnitSystem } from "~/lib/hooks";
 import {
@@ -52,7 +53,6 @@ import {
 	getWorkoutDetailsQuery,
 	getWorkoutTemplateDetailsQuery,
 } from "~/lib/state/fitness";
-import { BaseMediaDisplayItem } from "./media";
 
 export const getSetStatisticsTextToDisplay = (
 	lot: ExerciseLot,
diff --git a/apps/frontend/app/components/media.tsx b/apps/frontend/app/components/media.tsx
index 53ac30f68a..51a1571774 100644
--- a/apps/frontend/app/components/media.tsx
+++ b/apps/frontend/app/components/media.tsx
@@ -2,16 +2,10 @@ import {
 	ActionIcon,
 	Anchor,
 	Avatar,
-	Box,
-	Center,
-	Flex,
 	Group,
-	Image,
 	Loader,
-	type MantineStyleProp,
 	Menu,
 	ScrollArea,
-	Skeleton,
 	Text,
 	ThemeIcon,
 	Tooltip,
@@ -22,14 +16,13 @@ import { useInViewport } from "@mantine/hooks";
 import { Form, Link } from "@remix-run/react";
 import {
 	EntityLot,
-	GridPacking,
 	MetadataGroupDetailsDocument,
 	PersonDetailsDocument,
 	SeenState,
 	UserReviewScale,
 	UserToMediaReason,
 } from "@ryot/generated/graphql/backend/graphql";
-import { changeCase, getInitials, isString, snakeCase } from "@ryot/ts-utils";
+import { changeCase, snakeCase } from "@ryot/ts-utils";
 import {
 	IconBackpack,
 	IconBookmarks,
@@ -38,10 +31,11 @@ import {
 	IconStarFilled,
 } from "@tabler/icons-react";
 import { useQuery } from "@tanstack/react-query";
-import type { ReactNode, Ref } from "react";
+import type { ReactNode } from "react";
 import { match } from "ts-pattern";
 import { withQuery } from "ufo";
 import {
+	BaseMediaDisplayItem,
 	DisplayThreePointReview,
 	MEDIA_DETAILS_HEIGHT,
 } from "~/components/common";
@@ -54,7 +48,6 @@ import {
 } from "~/lib/generals";
 import {
 	useConfirmSubmit,
-	useFallbackImageUrl,
 	useUserDetails,
 	useUserMetadataDetails,
 	useUserPreferences,
@@ -110,137 +103,6 @@ export const MediaScrollArea = (props: { children: ReactNode }) => {
 	);
 };
 
-const blackBgStyles = {
-	backgroundColor: "rgba(0, 0, 0, 0.75)",
-	borderRadius: 3,
-	padding: 2,
-} satisfies MantineStyleProp;
-
-export const BaseMediaDisplayItem = (props: {
-	isLoading: boolean;
-	name?: string;
-	altName?: string;
-	imageUrl?: string | null;
-	imageOverlay?: {
-		topRight?: ReactNode;
-		topLeft?: ReactNode;
-		bottomRight?: ReactNode;
-		bottomLeft?: ReactNode;
-	};
-	labels?: { right?: ReactNode; left?: ReactNode };
-	onImageClickBehavior: string | (() => Promise<void>);
-	nameRight?: ReactNode;
-	innerRef?: Ref<HTMLDivElement>;
-}) => {
-	const userPreferences = useUserPreferences();
-	const gridPacking = userPreferences.general.gridPacking;
-	const SurroundingElement = (iProps: { children: ReactNode }) =>
-		isString(props.onImageClickBehavior) ? (
-			<Anchor component={Link} to={props.onImageClickBehavior}>
-				{iProps.children}
-			</Anchor>
-		) : (
-			<Box onClick={props.onImageClickBehavior}>{iProps.children}</Box>
-		);
-	const defaultOverlayProps = {
-		style: { zIndex: 10, ...blackBgStyles },
-		pos: "absolute",
-	} as const;
-
-	return (
-		<Flex justify="space-between" direction="column" ref={props.innerRef}>
-			<Box pos="relative" w="100%">
-				<SurroundingElement>
-					<Tooltip label={props.name} position="top">
-						<Image
-							src={props.imageUrl}
-							radius="md"
-							style={{
-								cursor: "pointer",
-								...match(gridPacking)
-									.with(GridPacking.Normal, () => ({ height: 260 }))
-									.with(GridPacking.Dense, () => ({ height: 180 }))
-									.exhaustive(),
-							}}
-							alt={`Image for ${props.name}`}
-							className={classes.mediaImage}
-							styles={{
-								root: {
-									transitionProperty: "transform",
-									transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
-									transitionDuration: "150ms",
-								},
-							}}
-							fallbackSrc={useFallbackImageUrl(
-								props.isLoading
-									? "Loading..."
-									: props.name
-										? getInitials(props.name)
-										: undefined,
-							)}
-						/>
-					</Tooltip>
-				</SurroundingElement>
-				{props.imageOverlay?.topLeft ? (
-					<Center top={5} left={5} {...defaultOverlayProps}>
-						{props.imageOverlay.topLeft}
-					</Center>
-				) : null}
-				{props.imageOverlay?.topRight ? (
-					<Center top={5} right={5} {...defaultOverlayProps}>
-						{props.imageOverlay.topRight}
-					</Center>
-				) : null}
-				{props.imageOverlay?.bottomLeft ? (
-					<Center bottom={5} left={5} {...defaultOverlayProps}>
-						{props.imageOverlay.bottomLeft}
-					</Center>
-				) : null}
-				{props.imageOverlay?.bottomRight ? (
-					<Center bottom={5} right={5} {...defaultOverlayProps}>
-						{props.imageOverlay.bottomRight}
-					</Center>
-				) : null}
-			</Box>
-			{props.isLoading ? (
-				<>
-					<Skeleton height={22} mt={10} />
-					<Skeleton height={22} mt={8} />
-				</>
-			) : (
-				<Flex
-					w="100%"
-					direction="column"
-					mt={2}
-					px={match(gridPacking)
-						.with(GridPacking.Normal, () => ({ base: 6, md: 3 }))
-						.with(GridPacking.Dense, () => ({ md: 2 }))
-						.exhaustive()}
-				>
-					<Flex w="100%" direction="row" justify="space-between">
-						<Text
-							size="sm"
-							c="dimmed"
-							visibleFrom={gridPacking === GridPacking.Dense ? "md" : undefined}
-						>
-							{props.labels?.left}
-						</Text>
-						<Text c="dimmed" size="sm">
-							{props.labels?.right}
-						</Text>
-					</Flex>
-					<Flex justify="space-between" align="center" mb="xs">
-						<Text w="100%" truncate fw="bold">
-							{props.altName ?? props.name}
-						</Text>
-						{props.nameRight}
-					</Flex>
-				</Flex>
-			)}
-		</Flex>
-	);
-};
-
 export const MetadataDisplayItem = (props: {
 	metadataId: string;
 	name?: string;
@@ -266,9 +128,12 @@ export const MetadataDisplayItem = (props: {
 		inViewport,
 	);
 	const averageRating = userMetadataDetails?.averageRating;
-	const history = (userMetadataDetails?.history || []).filter(
+	const completedHistory = (userMetadataDetails?.history || []).filter(
 		(h) => h.state === SeenState.Completed,
 	);
+	const currentProgress = userMetadataDetails?.history.find(
+		(h) => h.state === SeenState.InProgress,
+	)?.progress;
 	const surroundReason = (
 		idx: number,
 		data: readonly [UserToMediaReason, ReactNode],
@@ -291,11 +156,12 @@ export const MetadataDisplayItem = (props: {
 	return (
 		<BaseMediaDisplayItem
 			innerRef={ref}
-			name={props.name ?? metadataDetails?.title}
+			progress={currentProgress}
 			altName={props.altName}
+			imageUrl={metadataDetails?.image}
 			isLoading={isMetadataDetailsLoading}
+			name={props.name ?? metadataDetails?.title}
 			onImageClickBehavior={$path("/media/item/:id", { id: props.metadataId })}
-			imageUrl={metadataDetails?.image}
 			labels={
 				metadataDetails
 					? {
@@ -309,8 +175,8 @@ export const MetadataDisplayItem = (props: {
 									? changeCase(snakeCase(metadataDetails.lot))
 									: undefined) ||
 								(props.rightLabelHistory ? (
-									history.length > 0 ? (
-										`${history.length} time${history.length === 1 ? "" : "s"}`
+									completedHistory.length > 0 ? (
+										`${completedHistory.length} time${completedHistory.length === 1 ? "" : "s"}`
 									) : null
 								) : (
 									<Text c={hasInteracted ? "yellow" : undefined}>
diff --git a/apps/frontend/app/routes/_dashboard.media.$action.$lot.tsx b/apps/frontend/app/routes/_dashboard.media.$action.$lot.tsx
index 021e70bb4d..a7a7ce2055 100644
--- a/apps/frontend/app/routes/_dashboard.media.$action.$lot.tsx
+++ b/apps/frontend/app/routes/_dashboard.media.$action.$lot.tsx
@@ -55,11 +55,12 @@ import { z } from "zod";
 import { zx } from "zodix";
 import {
 	ApplicationGrid,
+	BaseMediaDisplayItem,
 	CollectionsFilter,
 	DebouncedSearchInput,
 	FiltersModal,
 } from "~/components/common";
-import { BaseMediaDisplayItem, MetadataDisplayItem } from "~/components/media";
+import { MetadataDisplayItem } from "~/components/media";
 import {
 	Verb,
 	commaDelimitedString,
diff --git a/apps/frontend/app/routes/_dashboard.media.groups.$action.tsx b/apps/frontend/app/routes/_dashboard.media.groups.$action.tsx
index 255b8455bb..d2555d11bc 100644
--- a/apps/frontend/app/routes/_dashboard.media.groups.$action.tsx
+++ b/apps/frontend/app/routes/_dashboard.media.groups.$action.tsx
@@ -47,10 +47,8 @@ import {
 	DebouncedSearchInput,
 	FiltersModal,
 } from "~/components/common";
-import {
-	BaseMediaDisplayItem,
-	MetadataGroupDisplayItem,
-} from "~/components/media";
+import { BaseMediaDisplayItem } from "~/components/common";
+import { MetadataGroupDisplayItem } from "~/components/media";
 import { commaDelimitedString, pageQueryParam } from "~/lib/generals";
 import { useAppSearchParam } from "~/lib/hooks";
 import { useBulkEditCollection } from "~/lib/state/collection";
diff --git a/apps/frontend/app/routes/_dashboard.media.people.$action.tsx b/apps/frontend/app/routes/_dashboard.media.people.$action.tsx
index 0a2a991915..46ae4c82fe 100644
--- a/apps/frontend/app/routes/_dashboard.media.people.$action.tsx
+++ b/apps/frontend/app/routes/_dashboard.media.people.$action.tsx
@@ -46,7 +46,8 @@ import {
 	DebouncedSearchInput,
 	FiltersModal,
 } from "~/components/common";
-import { BaseMediaDisplayItem, PersonDisplayItem } from "~/components/media";
+import { BaseMediaDisplayItem } from "~/components/common";
+import { PersonDisplayItem } from "~/components/media";
 import { commaDelimitedString, pageQueryParam } from "~/lib/generals";
 import { useAppSearchParam } from "~/lib/hooks";
 import { useBulkEditCollection } from "~/lib/state/collection";
diff --git a/apps/frontend/app/routes/_dashboard.settings.preferences.tsx b/apps/frontend/app/routes/_dashboard.settings.preferences.tsx
index a6b909467c..9032ca7d5f 100644
--- a/apps/frontend/app/routes/_dashboard.settings.preferences.tsx
+++ b/apps/frontend/app/routes/_dashboard.settings.preferences.tsx
@@ -6,7 +6,6 @@ import {
 	Button,
 	Container,
 	Divider,
-	Flex,
 	Group,
 	Input,
 	JsonInput,
@@ -32,7 +31,7 @@ import type {
 } from "@remix-run/node";
 import { Form, data, useLoaderData } from "@remix-run/react";
 import {
-	type DashboardElementLot,
+	DashboardElementLot,
 	GridPacking,
 	MediaLot,
 	MediaStateChanged,
@@ -646,6 +645,13 @@ export default function Page() {
 	);
 }
 
+const EDITABLE_NUM_ELEMENTS = [
+	DashboardElementLot.Upcoming,
+	DashboardElementLot.InProgress,
+	DashboardElementLot.Recommendations,
+];
+const EDITABLE_DEDUPLICATE_MEDIA = [DashboardElementLot.Upcoming];
+
 const EditDashboardElement = (props: {
 	isEditDisabled: boolean;
 	lot: DashboardElementLot;
@@ -668,7 +674,7 @@ const EditDashboardElement = (props: {
 					{...provided.draggableProps}
 					className={cn({ [classes.itemDragging]: snapshot.isDragging })}
 				>
-					<Group justify="space-between">
+					<Group justify="space-between" wrap="nowrap">
 						<Group>
 							<div
 								{...provided.dragHandleProps}
@@ -684,7 +690,9 @@ const EditDashboardElement = (props: {
 									stroke={1.5}
 								/>
 							</div>
-							<Title order={3}>{changeCase(props.lot)}</Title>
+							<Text fw="bold" fz={{ md: "lg", lg: "xl" }}>
+								{changeCase(props.lot)}
+							</Text>
 						</Group>
 						<Switch
 							label="Hidden"
@@ -704,13 +712,13 @@ const EditDashboardElement = (props: {
 							}}
 						/>
 					</Group>
-					{isNumber(focusedElement.numElements) ? (
-						<Flex>
+					<Group gap="xl" wrap="nowrap">
+						{EDITABLE_NUM_ELEMENTS.includes(props.lot) ? (
 							<NumberInput
-								label="Number of elements"
 								size="xs"
-								defaultValue={focusedElement.numElements}
+								label="Number of elements"
 								disabled={!!props.isEditDisabled}
+								defaultValue={focusedElement.numElements || undefined}
 								onChange={(num) => {
 									if (isNumber(num)) {
 										const newDashboardData = Array.from(
@@ -724,8 +732,30 @@ const EditDashboardElement = (props: {
 									}
 								}}
 							/>
-						</Flex>
-					) : null}
+						) : null}
+						{EDITABLE_DEDUPLICATE_MEDIA.includes(props.lot) ? (
+							<Switch
+								size="xs"
+								label="Deduplicate media"
+								disabled={!!props.isEditDisabled}
+								defaultChecked={focusedElement.deduplicateMedia || undefined}
+								styles={{ description: { width: rem(200) } }}
+								description="If there's more than one episode of a media, keep the first one"
+								onChange={(ev) => {
+									const newValue = ev.currentTarget.checked;
+									const newDashboardData = Array.from(
+										userPreferences.general.dashboard,
+									);
+									newDashboardData[focusedElementIndex].deduplicateMedia =
+										newValue;
+									props.appendPref(
+										"general.dashboard",
+										JSON.stringify(newDashboardData),
+									);
+								}}
+							/>
+						) : null}
+					</Group>
 				</Paper>
 			)}
 		</Draggable>
@@ -734,11 +764,11 @@ const EditDashboardElement = (props: {
 
 const reorder = <T,>(
 	array: Array<T>,
-	{ from, to }: { from: number; to: number },
+	details: { from: number; to: number },
 ) => {
 	const cloned = [...array];
-	const item = array[from];
-	cloned.splice(from, 1);
-	cloned.splice(to, 0, item);
+	const item = array[details.from];
+	cloned.splice(details.from, 1);
+	cloned.splice(details.to, 0, item);
 	return cloned;
 };
diff --git a/apps/frontend/app/routes/_dashboard.tsx b/apps/frontend/app/routes/_dashboard.tsx
index 24bc79f7ea..7648999d60 100644
--- a/apps/frontend/app/routes/_dashboard.tsx
+++ b/apps/frontend/app/routes/_dashboard.tsx
@@ -1573,6 +1573,7 @@ const AddEntityToCollectionForm = ({
 			method="POST"
 			onSubmit={(e) => {
 				submit(e);
+				refreshUserMetadataDetails(addEntityToCollectionData.entityId);
 				closeAddEntityToCollectionModal();
 			}}
 			action={withQuery("/actions", { intent: "addEntityToCollection" })}
diff --git a/apps/frontend/package.json b/apps/frontend/package.json
index 4d67783249..f1bb925985 100644
--- a/apps/frontend/package.json
+++ b/apps/frontend/package.json
@@ -27,7 +27,7 @@
 		"@ryot/generated": "workspace:*",
 		"@ryot/graphql": "workspace:*",
 		"@ryot/ts-utils": "workspace:*",
-		"@tabler/icons-react": "3.21.0",
+		"@tabler/icons-react": "3.17.0",
 		"@tanstack/react-query": "5.59.16",
 		"@tanstack/react-query-devtools": "5.59.16",
 		"buffer": "6.0.3",
@@ -53,7 +53,7 @@
 		"react-dom": "18.3.1",
 		"react-virtuoso": "4.12.0",
 		"react-webcam": "7.2.0",
-		"recharts": "2.13.1",
+		"recharts": "2.13.3",
 		"remix-routes": "1.7.7",
 		"remix-utils": "7.7.0",
 		"tailwind-merge": "2.5.4",
@@ -79,8 +79,8 @@
 		"postcss": "8.4.47",
 		"postcss-preset-mantine": "1.17.0",
 		"postcss-simple-vars": "7.0.1",
-		"remix-development-tools": "4.7.3",
-		"ts-essentials": "10.0.2",
+		"remix-development-tools": "4.7.5",
+		"ts-essentials": "10.0.3",
 		"typescript": "5.6.3",
 		"typescript-plugin-css-modules": "5.1.0",
 		"typescript-remix-routes-plugin": "1.0.1",
diff --git a/apps/website/app/root.tsx b/apps/website/app/root.tsx
index 7ce77b0b33..60988cc6fa 100644
--- a/apps/website/app/root.tsx
+++ b/apps/website/app/root.tsx
@@ -81,7 +81,7 @@ export default function App() {
 						<nav className="ml-auto flex gap-4 sm:gap-6">
 							<Link
 								to={$path("/features")}
-								className="text-sm font-medium hover:underline underline-offset-4 hidden md:block"
+								className="text-sm font-medium hover:underline underline-offset-4"
 							>
 								Features
 							</Link>
@@ -107,7 +107,7 @@ export default function App() {
 							</a>
 							<Link
 								to={withFragment($path("/"), "contact")}
-								className="text-sm font-medium hover:underline underline-offset-4"
+								className="text-sm font-medium hover:underline underline-offset-4 hidden md:block"
 							>
 								Contact Us
 							</Link>
diff --git a/apps/website/app/routes/features.tsx b/apps/website/app/routes/features.tsx
index 8675440711..c06528c238 100644
--- a/apps/website/app/routes/features.tsx
+++ b/apps/website/app/routes/features.tsx
@@ -37,8 +37,6 @@ import {
 	Carousel,
 	CarouselContent,
 	CarouselItem,
-	CarouselNext,
-	CarouselPrevious,
 } from "~/lib/components/ui/carousel";
 import { logoUrl } from "~/lib/utils";
 
@@ -80,7 +78,10 @@ export default function Page() {
 						{data.heading}
 					</h2>
 					{data.images.length > 0 ? (
-						<Carousel plugins={[Autoplay({ delay: 5000 })]}>
+						<Carousel
+							plugins={[Autoplay({ delay: 5000 })]}
+							className="w-screen"
+						>
 							<CarouselContent>
 								{data.images.map((image, index) => (
 									<CarouselItem key={image} className="flex flex-col space-y-4">
@@ -92,10 +93,6 @@ export default function Page() {
 									</CarouselItem>
 								))}
 							</CarouselContent>
-							<div className="hidden md:block">
-								<CarouselPrevious />
-								<CarouselNext />
-							</div>
 						</Carousel>
 					) : null}
 					<div className="px-2 md:px-0 mx-auto grid items-start gap-5 md:gap-8 sm:max-w-4xl sm:grid-cols-2 lg:max-w-5xl lg:grid-cols-3">
diff --git a/apps/website/app/routes/me.tsx b/apps/website/app/routes/me.tsx
index 6acb7df8fa..9d6e22de6f 100644
--- a/apps/website/app/routes/me.tsx
+++ b/apps/website/app/routes/me.tsx
@@ -15,6 +15,7 @@ import {
 	formatDateToNaiveDate,
 	getActionIntent,
 } from "@ryot/ts-utils";
+import { Unkey } from "@unkey/api";
 import dayjs from "dayjs";
 import { eq } from "drizzle-orm";
 import { useEffect, useState } from "react";
@@ -59,6 +60,9 @@ export const action = async ({ request }: ActionFunctionArgs) => {
 		.with("regenerateUnkeyKey", async () => {
 			const customer = await getCustomerFromCookie(request);
 			if (!customer || !customer.planType) throw new Error("No customer found");
+			if (!customer.unkeyKeyId) throw new Error("No unkey key found");
+			const unkey = new Unkey({ rootKey: serverVariables.UNKEY_ROOT_KEY });
+			await unkey.keys.update({ keyId: customer.unkeyKeyId, enabled: false });
 			const renewOn = customer.renewOn ? dayjs(customer.renewOn) : undefined;
 			const created = await createUnkeyKey(customer, renewOn);
 			await db
@@ -209,7 +213,7 @@ export default function Index() {
 			<Form
 				method="POST"
 				action={withQuery(".", { intent: "logout" })}
-				className="flex w-full items-end justify-end px-4 md:px-10 pb-6"
+				className="flex w-full items-end justify-end mt-4 md:mt-0 md:px-10 pb-6"
 			>
 				<Button type="submit">Sign out</Button>
 			</Form>
diff --git a/apps/website/package.json b/apps/website/package.json
index 974fb4b909..9ca495d325 100644
--- a/apps/website/package.json
+++ b/apps/website/package.json
@@ -14,7 +14,7 @@
 		"@radix-ui/react-label": "2.1.0",
 		"@radix-ui/react-slot": "1.1.0",
 		"@radix-ui/react-tooltip": "1.1.3",
-		"@react-email/components": "0.0.25",
+		"@react-email/components": "0.0.26",
 		"@remix-run/node": "2.13.1",
 		"@remix-run/react": "2.13.1",
 		"@remix-run/serve": "2.13.1",
@@ -22,7 +22,7 @@
 		"@ryot/graphql": "workspace:*",
 		"@ryot/transactional": "workspace:*",
 		"@ryot/ts-utils": "workspace:*",
-		"@tabler/icons-react": "3.21.0",
+		"@tabler/icons-react": "3.17.0",
 		"@unkey/api": "0.26.2",
 		"class-variance-authority": "0.7.0",
 		"clsx": "2.1.1",
@@ -34,7 +34,7 @@
 		"graphql": "16.9.0",
 		"graphql-request": "7.1.0",
 		"humanize-duration-ts": "2.1.1",
-		"input-otp": "1.2.5",
+		"input-otp": "1.4.0",
 		"isbot": "5.1.17",
 		"lodash": "4.17.21",
 		"lucide-react": "0.454.0",
diff --git a/crates/models/user/src/lib.rs b/crates/models/user/src/lib.rs
index cc13159b6f..836774aa89 100644
--- a/crates/models/user/src/lib.rs
+++ b/crates/models/user/src/lib.rs
@@ -238,11 +238,14 @@ pub enum UserReviewScale {
     ThreePointSmiley,
 }
 
-#[derive(Debug, Serialize, Deserialize, Enum, Clone, Eq, PartialEq, FromJsonQueryResult, Copy)]
+#[derive(
+    Debug, Serialize, Deserialize, Enum, Clone, Eq, PartialEq, FromJsonQueryResult, Copy, Default,
+)]
 #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
 pub enum DashboardElementLot {
     Upcoming,
     InProgress,
+    #[default]
     Summary,
     Recommendations,
     Activity,
@@ -250,13 +253,14 @@ pub enum DashboardElementLot {
 
 #[skip_serializing_none]
 #[derive(
-    Debug, Serialize, Deserialize, SimpleObject, Clone, Eq, PartialEq, FromJsonQueryResult,
+    Debug, Serialize, Deserialize, SimpleObject, Clone, Eq, PartialEq, FromJsonQueryResult, Default,
 )]
 #[serde(rename_all = "camelCase")]
 pub struct UserGeneralDashboardElement {
-    pub section: DashboardElementLot,
     pub hidden: bool,
     pub num_elements: Option<u64>,
+    pub section: DashboardElementLot,
+    pub deduplicate_media: Option<bool>,
 }
 
 #[skip_serializing_none]
@@ -302,29 +306,28 @@ pub struct UserGeneralPreferences {
     pub disable_navigation_animation: bool,
     #[educe(Default(expression = vec![
         UserGeneralDashboardElement {
-            section: DashboardElementLot::Upcoming,
-            hidden: false,
             num_elements: Some(8),
+            deduplicate_media: Some(true),
+            section: DashboardElementLot::Upcoming,
+            ..Default::default()
         },
         UserGeneralDashboardElement {
-            section: DashboardElementLot::InProgress,
-            hidden: false,
             num_elements: Some(8),
+            section: DashboardElementLot::InProgress,
+            ..Default::default()
         },
         UserGeneralDashboardElement {
             section: DashboardElementLot::Summary,
-            hidden: false,
-            num_elements: None,
+            ..Default::default()
         },
         UserGeneralDashboardElement {
-            section: DashboardElementLot::Recommendations,
-            hidden: false,
             num_elements: Some(8),
+            section: DashboardElementLot::Recommendations,
+            ..Default::default()
         },
         UserGeneralDashboardElement {
             section: DashboardElementLot::Activity,
-            hidden: false,
-            num_elements: None,
+            ..Default::default()
         },
     ]))]
     pub dashboard: Vec<UserGeneralDashboardElement>,
diff --git a/crates/services/miscellaneous/src/lib.rs b/crates/services/miscellaneous/src/lib.rs
index 7f8adee788..ddb4ccc1f1 100644
--- a/crates/services/miscellaneous/src/lib.rs
+++ b/crates/services/miscellaneous/src/lib.rs
@@ -111,7 +111,7 @@ use serde::{Deserialize, Serialize};
 use supporting_service::SupportingService;
 use tokio::time::{sleep, Duration as TokioDuration};
 use traits::{MediaProvider, MediaProviderLanguages, TraceOk};
-use user_models::UserReviewScale;
+use user_models::{DashboardElementLot, UserReviewScale};
 use uuid::Uuid;
 
 type Provider = Box<(dyn MediaProvider + Send + Sync)>;
@@ -797,7 +797,7 @@ ORDER BY RANDOM() LIMIT 10;
             .column(Asterisk)
             .from_subquery(
                 CalendarEvent::find()
-                    .apply_if(deduplicate, |query, _v| {
+                    .apply_if(deduplicate.filter(|&d| d), |query, _v| {
                         query
                             .distinct_on([(
                                 AliasedCalendarEvent::Table,
@@ -946,6 +946,11 @@ ORDER BY RANDOM() LIMIT 10;
                 (None, from_date.checked_add_days(Days::new(d)))
             }
         };
+        let preferences = user_by_id(&user_id, &self.0).await?.preferences.general;
+        let element = preferences
+            .dashboard
+            .iter()
+            .find(|e| matches!(e.section, DashboardElementLot::Upcoming));
         let events = self
             .get_calendar_events(
                 user_id,
@@ -953,7 +958,7 @@ ORDER BY RANDOM() LIMIT 10;
                 to_date,
                 Some(from_date),
                 media_limit,
-                Some(true),
+                element.and_then(|e| e.deduplicate_media),
             )
             .await?;
         Ok(events)
diff --git a/libs/generated/src/graphql/backend/gql.ts b/libs/generated/src/graphql/backend/gql.ts
index c789ce8269..04547e0479 100644
--- a/libs/generated/src/graphql/backend/gql.ts
+++ b/libs/generated/src/graphql/backend/gql.ts
@@ -31,7 +31,7 @@ const documents = {
     "query MetadataSearch($input: MetadataSearchInput!) {\n  metadataSearch(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items {\n      databaseId\n      hasInteracted\n      item {\n        identifier\n        title\n        image\n        publishYear\n      }\n    }\n  }\n}": types.MetadataSearchDocument,
     "query PeopleSearch($input: PeopleSearchInput!) {\n  peopleSearch(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items {\n      identifier\n      name\n      image\n      birthYear\n    }\n  }\n}": types.PeopleSearchDocument,
     "query PersonDetails($personId: String!) {\n  personDetails(personId: $personId) {\n    sourceUrl\n    details {\n      id\n      name\n      source\n      identifier\n      isPartial\n      description\n      birthDate\n      deathDate\n      place\n      website\n      gender\n      displayImages\n    }\n    contents {\n      name\n      count\n      items {\n        character\n        metadataId\n      }\n    }\n  }\n}": types.PersonDetailsDocument,
-    "query UserDetails {\n  userDetails {\n    __typename\n    ... on User {\n      id\n      lot\n      name\n      isDisabled\n      oidcIssuerId\n      preferences {\n        general {\n          reviewScale\n          gridPacking\n          displayNsfw\n          disableVideos\n          persistQueries\n          disableReviews\n          disableIntegrations\n          disableWatchProviders\n          disableNavigationAnimation\n          dashboard {\n            section\n            hidden\n            numElements\n          }\n          watchProviders {\n            lot\n            values\n          }\n        }\n        fitness {\n          logging {\n            showDetailsWhileEditing\n          }\n          exercises {\n            unitSystem\n            setRestTimers {\n              ...SetRestTimersPart\n            }\n          }\n          measurements {\n            custom {\n              name\n              dataType\n            }\n            inbuilt {\n              weight\n              bodyMassIndex\n              totalBodyWater\n              muscle\n              leanBodyMass\n              bodyFat\n              boneMass\n              visceralFat\n              waistCircumference\n              waistToHeightRatio\n              hipCircumference\n              waistToHipRatio\n              chestCircumference\n              thighCircumference\n              bicepsCircumference\n              neckCircumference\n              bodyFatCaliper\n              chestSkinfold\n              abdominalSkinfold\n              thighSkinfold\n              basalMetabolicRate\n              totalDailyEnergyExpenditure\n              calories\n            }\n          }\n        }\n        notifications {\n          toSend\n          enabled\n        }\n        featuresEnabled {\n          others {\n            calendar\n            collections\n          }\n          fitness {\n            enabled\n            workouts\n            templates\n            measurements\n          }\n          media {\n            enabled\n            anime\n            audioBook\n            book\n            manga\n            movie\n            podcast\n            show\n            videoGame\n            visualNovel\n            people\n            groups\n            genres\n          }\n        }\n      }\n    }\n  }\n}": types.UserDetailsDocument,
+    "query UserDetails {\n  userDetails {\n    __typename\n    ... on User {\n      id\n      lot\n      name\n      isDisabled\n      oidcIssuerId\n      preferences {\n        general {\n          reviewScale\n          gridPacking\n          displayNsfw\n          disableVideos\n          persistQueries\n          disableReviews\n          disableIntegrations\n          disableWatchProviders\n          disableNavigationAnimation\n          dashboard {\n            hidden\n            section\n            numElements\n            deduplicateMedia\n          }\n          watchProviders {\n            lot\n            values\n          }\n        }\n        fitness {\n          logging {\n            showDetailsWhileEditing\n          }\n          exercises {\n            unitSystem\n            setRestTimers {\n              ...SetRestTimersPart\n            }\n          }\n          measurements {\n            custom {\n              name\n              dataType\n            }\n            inbuilt {\n              weight\n              bodyMassIndex\n              totalBodyWater\n              muscle\n              leanBodyMass\n              bodyFat\n              boneMass\n              visceralFat\n              waistCircumference\n              waistToHeightRatio\n              hipCircumference\n              waistToHipRatio\n              chestCircumference\n              thighCircumference\n              bicepsCircumference\n              neckCircumference\n              bodyFatCaliper\n              chestSkinfold\n              abdominalSkinfold\n              thighSkinfold\n              basalMetabolicRate\n              totalDailyEnergyExpenditure\n              calories\n            }\n          }\n        }\n        notifications {\n          toSend\n          enabled\n        }\n        featuresEnabled {\n          others {\n            calendar\n            collections\n          }\n          fitness {\n            enabled\n            workouts\n            templates\n            measurements\n          }\n          media {\n            enabled\n            anime\n            audioBook\n            book\n            manga\n            movie\n            podcast\n            show\n            videoGame\n            visualNovel\n            people\n            groups\n            genres\n          }\n        }\n      }\n    }\n  }\n}": types.UserDetailsDocument,
     "query UserExerciseDetails($exerciseId: String!) {\n  userExerciseDetails(exerciseId: $exerciseId) {\n    collections {\n      ...CollectionPart\n    }\n    reviews {\n      ...ReviewItemPart\n    }\n    history {\n      idx\n      workoutId\n      workoutEndOn\n      bestSet {\n        ...WorkoutSetRecordPart\n      }\n    }\n    details {\n      exerciseId\n      createdOn\n      lastUpdatedOn\n      exerciseNumTimesInteracted\n      exerciseExtraInformation {\n        settings {\n          setRestTimers {\n            ...SetRestTimersPart\n          }\n        }\n        lifetimeStats {\n          weight\n          reps\n          distance\n          duration\n          personalBestsAchieved\n        }\n        personalBests {\n          lot\n          sets {\n            workoutId\n            exerciseIdx\n            setIdx\n          }\n        }\n      }\n    }\n  }\n}": types.UserExerciseDetailsDocument,
     "query UserMeasurementsList($input: UserMeasurementsListInput!) {\n  userMeasurementsList(input: $input) {\n    timestamp\n    name\n    comment\n    stats {\n      weight\n      bodyMassIndex\n      totalBodyWater\n      muscle\n      leanBodyMass\n      bodyFat\n      boneMass\n      visceralFat\n      waistCircumference\n      waistToHeightRatio\n      hipCircumference\n      waistToHipRatio\n      chestCircumference\n      thighCircumference\n      bicepsCircumference\n      neckCircumference\n      bodyFatCaliper\n      chestSkinfold\n      abdominalSkinfold\n      thighSkinfold\n      basalMetabolicRate\n      totalDailyEnergyExpenditure\n      calories\n      custom\n    }\n  }\n}": types.UserMeasurementsListDocument,
     "query UserMetadataDetails($metadataId: String!) {\n  userMetadataDetails(metadataId: $metadataId) {\n    mediaReason\n    hasInteracted\n    collections {\n      ...CollectionPart\n    }\n    inProgress {\n      ...SeenPart\n    }\n    history {\n      ...SeenPart\n    }\n    averageRating\n    reviews {\n      ...ReviewItemPart\n    }\n    seenByAllCount\n    seenByUserCount\n    nextEntry {\n      season\n      volume\n      episode\n      chapter\n    }\n    showProgress {\n      timesSeen\n      seasonNumber\n      episodes {\n        episodeNumber\n        timesSeen\n      }\n    }\n    podcastProgress {\n      episodeNumber\n      timesSeen\n    }\n  }\n}": types.UserMetadataDetailsDocument,
@@ -130,7 +130,7 @@ export function graphql(source: "query PersonDetails($personId: String!) {\n  pe
 /**
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
  */
-export function graphql(source: "query UserDetails {\n  userDetails {\n    __typename\n    ... on User {\n      id\n      lot\n      name\n      isDisabled\n      oidcIssuerId\n      preferences {\n        general {\n          reviewScale\n          gridPacking\n          displayNsfw\n          disableVideos\n          persistQueries\n          disableReviews\n          disableIntegrations\n          disableWatchProviders\n          disableNavigationAnimation\n          dashboard {\n            section\n            hidden\n            numElements\n          }\n          watchProviders {\n            lot\n            values\n          }\n        }\n        fitness {\n          logging {\n            showDetailsWhileEditing\n          }\n          exercises {\n            unitSystem\n            setRestTimers {\n              ...SetRestTimersPart\n            }\n          }\n          measurements {\n            custom {\n              name\n              dataType\n            }\n            inbuilt {\n              weight\n              bodyMassIndex\n              totalBodyWater\n              muscle\n              leanBodyMass\n              bodyFat\n              boneMass\n              visceralFat\n              waistCircumference\n              waistToHeightRatio\n              hipCircumference\n              waistToHipRatio\n              chestCircumference\n              thighCircumference\n              bicepsCircumference\n              neckCircumference\n              bodyFatCaliper\n              chestSkinfold\n              abdominalSkinfold\n              thighSkinfold\n              basalMetabolicRate\n              totalDailyEnergyExpenditure\n              calories\n            }\n          }\n        }\n        notifications {\n          toSend\n          enabled\n        }\n        featuresEnabled {\n          others {\n            calendar\n            collections\n          }\n          fitness {\n            enabled\n            workouts\n            templates\n            measurements\n          }\n          media {\n            enabled\n            anime\n            audioBook\n            book\n            manga\n            movie\n            podcast\n            show\n            videoGame\n            visualNovel\n            people\n            groups\n            genres\n          }\n        }\n      }\n    }\n  }\n}"): (typeof documents)["query UserDetails {\n  userDetails {\n    __typename\n    ... on User {\n      id\n      lot\n      name\n      isDisabled\n      oidcIssuerId\n      preferences {\n        general {\n          reviewScale\n          gridPacking\n          displayNsfw\n          disableVideos\n          persistQueries\n          disableReviews\n          disableIntegrations\n          disableWatchProviders\n          disableNavigationAnimation\n          dashboard {\n            section\n            hidden\n            numElements\n          }\n          watchProviders {\n            lot\n            values\n          }\n        }\n        fitness {\n          logging {\n            showDetailsWhileEditing\n          }\n          exercises {\n            unitSystem\n            setRestTimers {\n              ...SetRestTimersPart\n            }\n          }\n          measurements {\n            custom {\n              name\n              dataType\n            }\n            inbuilt {\n              weight\n              bodyMassIndex\n              totalBodyWater\n              muscle\n              leanBodyMass\n              bodyFat\n              boneMass\n              visceralFat\n              waistCircumference\n              waistToHeightRatio\n              hipCircumference\n              waistToHipRatio\n              chestCircumference\n              thighCircumference\n              bicepsCircumference\n              neckCircumference\n              bodyFatCaliper\n              chestSkinfold\n              abdominalSkinfold\n              thighSkinfold\n              basalMetabolicRate\n              totalDailyEnergyExpenditure\n              calories\n            }\n          }\n        }\n        notifications {\n          toSend\n          enabled\n        }\n        featuresEnabled {\n          others {\n            calendar\n            collections\n          }\n          fitness {\n            enabled\n            workouts\n            templates\n            measurements\n          }\n          media {\n            enabled\n            anime\n            audioBook\n            book\n            manga\n            movie\n            podcast\n            show\n            videoGame\n            visualNovel\n            people\n            groups\n            genres\n          }\n        }\n      }\n    }\n  }\n}"];
+export function graphql(source: "query UserDetails {\n  userDetails {\n    __typename\n    ... on User {\n      id\n      lot\n      name\n      isDisabled\n      oidcIssuerId\n      preferences {\n        general {\n          reviewScale\n          gridPacking\n          displayNsfw\n          disableVideos\n          persistQueries\n          disableReviews\n          disableIntegrations\n          disableWatchProviders\n          disableNavigationAnimation\n          dashboard {\n            hidden\n            section\n            numElements\n            deduplicateMedia\n          }\n          watchProviders {\n            lot\n            values\n          }\n        }\n        fitness {\n          logging {\n            showDetailsWhileEditing\n          }\n          exercises {\n            unitSystem\n            setRestTimers {\n              ...SetRestTimersPart\n            }\n          }\n          measurements {\n            custom {\n              name\n              dataType\n            }\n            inbuilt {\n              weight\n              bodyMassIndex\n              totalBodyWater\n              muscle\n              leanBodyMass\n              bodyFat\n              boneMass\n              visceralFat\n              waistCircumference\n              waistToHeightRatio\n              hipCircumference\n              waistToHipRatio\n              chestCircumference\n              thighCircumference\n              bicepsCircumference\n              neckCircumference\n              bodyFatCaliper\n              chestSkinfold\n              abdominalSkinfold\n              thighSkinfold\n              basalMetabolicRate\n              totalDailyEnergyExpenditure\n              calories\n            }\n          }\n        }\n        notifications {\n          toSend\n          enabled\n        }\n        featuresEnabled {\n          others {\n            calendar\n            collections\n          }\n          fitness {\n            enabled\n            workouts\n            templates\n            measurements\n          }\n          media {\n            enabled\n            anime\n            audioBook\n            book\n            manga\n            movie\n            podcast\n            show\n            videoGame\n            visualNovel\n            people\n            groups\n            genres\n          }\n        }\n      }\n    }\n  }\n}"): (typeof documents)["query UserDetails {\n  userDetails {\n    __typename\n    ... on User {\n      id\n      lot\n      name\n      isDisabled\n      oidcIssuerId\n      preferences {\n        general {\n          reviewScale\n          gridPacking\n          displayNsfw\n          disableVideos\n          persistQueries\n          disableReviews\n          disableIntegrations\n          disableWatchProviders\n          disableNavigationAnimation\n          dashboard {\n            hidden\n            section\n            numElements\n            deduplicateMedia\n          }\n          watchProviders {\n            lot\n            values\n          }\n        }\n        fitness {\n          logging {\n            showDetailsWhileEditing\n          }\n          exercises {\n            unitSystem\n            setRestTimers {\n              ...SetRestTimersPart\n            }\n          }\n          measurements {\n            custom {\n              name\n              dataType\n            }\n            inbuilt {\n              weight\n              bodyMassIndex\n              totalBodyWater\n              muscle\n              leanBodyMass\n              bodyFat\n              boneMass\n              visceralFat\n              waistCircumference\n              waistToHeightRatio\n              hipCircumference\n              waistToHipRatio\n              chestCircumference\n              thighCircumference\n              bicepsCircumference\n              neckCircumference\n              bodyFatCaliper\n              chestSkinfold\n              abdominalSkinfold\n              thighSkinfold\n              basalMetabolicRate\n              totalDailyEnergyExpenditure\n              calories\n            }\n          }\n        }\n        notifications {\n          toSend\n          enabled\n        }\n        featuresEnabled {\n          others {\n            calendar\n            collections\n          }\n          fitness {\n            enabled\n            workouts\n            templates\n            measurements\n          }\n          media {\n            enabled\n            anime\n            audioBook\n            book\n            manga\n            movie\n            podcast\n            show\n            videoGame\n            visualNovel\n            people\n            groups\n            genres\n          }\n        }\n      }\n    }\n  }\n}"];
 /**
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
  */
diff --git a/libs/generated/src/graphql/backend/graphql.ts b/libs/generated/src/graphql/backend/graphql.ts
index 4247093d64..d9a44fb905 100644
--- a/libs/generated/src/graphql/backend/graphql.ts
+++ b/libs/generated/src/graphql/backend/graphql.ts
@@ -2251,6 +2251,7 @@ export type UserFitnessPreferences = {
 };
 
 export type UserGeneralDashboardElement = {
+  deduplicateMedia?: Maybe<Scalars['Boolean']['output']>;
   hidden: Scalars['Boolean']['output'];
   numElements?: Maybe<Scalars['Int']['output']>;
   section: DashboardElementLot;
@@ -3171,7 +3172,7 @@ export type PersonDetailsQuery = { personDetails: { sourceUrl?: string | null, d
 export type UserDetailsQueryVariables = Exact<{ [key: string]: never; }>;
 
 
-export type UserDetailsQuery = { userDetails: { __typename: 'User', id: string, lot: UserLot, name: string, isDisabled?: boolean | null, oidcIssuerId?: string | null, preferences: { general: { reviewScale: UserReviewScale, gridPacking: GridPacking, displayNsfw: boolean, disableVideos: boolean, persistQueries: boolean, disableReviews: boolean, disableIntegrations: boolean, disableWatchProviders: boolean, disableNavigationAnimation: boolean, dashboard: Array<{ section: DashboardElementLot, hidden: boolean, numElements?: number | null }>, watchProviders: Array<{ lot: MediaLot, values: Array<string> }> }, fitness: { logging: { showDetailsWhileEditing: boolean }, exercises: { unitSystem: UserUnitSystem, setRestTimers: { drop?: number | null, warmup?: number | null, normal?: number | null, failure?: number | null } }, measurements: { custom: Array<{ name: string, dataType: UserCustomMeasurementDataType }>, inbuilt: { weight: boolean, bodyMassIndex: boolean, totalBodyWater: boolean, muscle: boolean, leanBodyMass: boolean, bodyFat: boolean, boneMass: boolean, visceralFat: boolean, waistCircumference: boolean, waistToHeightRatio: boolean, hipCircumference: boolean, waistToHipRatio: boolean, chestCircumference: boolean, thighCircumference: boolean, bicepsCircumference: boolean, neckCircumference: boolean, bodyFatCaliper: boolean, chestSkinfold: boolean, abdominalSkinfold: boolean, thighSkinfold: boolean, basalMetabolicRate: boolean, totalDailyEnergyExpenditure: boolean, calories: boolean } } }, notifications: { toSend: Array<MediaStateChanged>, enabled: boolean }, featuresEnabled: { others: { calendar: boolean, collections: boolean }, fitness: { enabled: boolean, workouts: boolean, templates: boolean, measurements: boolean }, media: { enabled: boolean, anime: boolean, audioBook: boolean, book: boolean, manga: boolean, movie: boolean, podcast: boolean, show: boolean, videoGame: boolean, visualNovel: boolean, people: boolean, groups: boolean, genres: boolean } } } } | { __typename: 'UserDetailsError' } };
+export type UserDetailsQuery = { userDetails: { __typename: 'User', id: string, lot: UserLot, name: string, isDisabled?: boolean | null, oidcIssuerId?: string | null, preferences: { general: { reviewScale: UserReviewScale, gridPacking: GridPacking, displayNsfw: boolean, disableVideos: boolean, persistQueries: boolean, disableReviews: boolean, disableIntegrations: boolean, disableWatchProviders: boolean, disableNavigationAnimation: boolean, dashboard: Array<{ hidden: boolean, section: DashboardElementLot, numElements?: number | null, deduplicateMedia?: boolean | null }>, watchProviders: Array<{ lot: MediaLot, values: Array<string> }> }, fitness: { logging: { showDetailsWhileEditing: boolean }, exercises: { unitSystem: UserUnitSystem, setRestTimers: { drop?: number | null, warmup?: number | null, normal?: number | null, failure?: number | null } }, measurements: { custom: Array<{ name: string, dataType: UserCustomMeasurementDataType }>, inbuilt: { weight: boolean, bodyMassIndex: boolean, totalBodyWater: boolean, muscle: boolean, leanBodyMass: boolean, bodyFat: boolean, boneMass: boolean, visceralFat: boolean, waistCircumference: boolean, waistToHeightRatio: boolean, hipCircumference: boolean, waistToHipRatio: boolean, chestCircumference: boolean, thighCircumference: boolean, bicepsCircumference: boolean, neckCircumference: boolean, bodyFatCaliper: boolean, chestSkinfold: boolean, abdominalSkinfold: boolean, thighSkinfold: boolean, basalMetabolicRate: boolean, totalDailyEnergyExpenditure: boolean, calories: boolean } } }, notifications: { toSend: Array<MediaStateChanged>, enabled: boolean }, featuresEnabled: { others: { calendar: boolean, collections: boolean }, fitness: { enabled: boolean, workouts: boolean, templates: boolean, measurements: boolean }, media: { enabled: boolean, anime: boolean, audioBook: boolean, book: boolean, manga: boolean, movie: boolean, podcast: boolean, show: boolean, videoGame: boolean, visualNovel: boolean, people: boolean, groups: boolean, genres: boolean } } } } | { __typename: 'UserDetailsError' } };
 
 export type UserExerciseDetailsQueryVariables = Exact<{
   exerciseId: Scalars['String']['input'];
@@ -3462,7 +3463,7 @@ export const MetadataListDocument = {"kind":"Document","definitions":[{"kind":"O
 export const MetadataSearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MetadataSearch"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MetadataSearchInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"metadataSearch"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"nextPage"}}]}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"databaseId"}},{"kind":"Field","name":{"kind":"Name","value":"hasInteracted"}},{"kind":"Field","name":{"kind":"Name","value":"item"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"image"}},{"kind":"Field","name":{"kind":"Name","value":"publishYear"}}]}}]}}]}}]}}]} as unknown as DocumentNode<MetadataSearchQuery, MetadataSearchQueryVariables>;
 export const PeopleSearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PeopleSearch"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PeopleSearchInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"peopleSearch"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"nextPage"}}]}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"image"}},{"kind":"Field","name":{"kind":"Name","value":"birthYear"}}]}}]}}]}}]} as unknown as DocumentNode<PeopleSearchQuery, PeopleSearchQueryVariables>;
 export const PersonDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PersonDetails"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"personId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personDetails"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"personId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"personId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sourceUrl"}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"source"}},{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"isPartial"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"birthDate"}},{"kind":"Field","name":{"kind":"Name","value":"deathDate"}},{"kind":"Field","name":{"kind":"Name","value":"place"}},{"kind":"Field","name":{"kind":"Name","value":"website"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"displayImages"}}]}},{"kind":"Field","name":{"kind":"Name","value":"contents"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"character"}},{"kind":"Field","name":{"kind":"Name","value":"metadataId"}}]}}]}}]}}]}}]} as unknown as DocumentNode<PersonDetailsQuery, PersonDetailsQueryVariables>;
-export const UserDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserDetails"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userDetails"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"isDisabled"}},{"kind":"Field","name":{"kind":"Name","value":"oidcIssuerId"}},{"kind":"Field","name":{"kind":"Name","value":"preferences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"general"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"reviewScale"}},{"kind":"Field","name":{"kind":"Name","value":"gridPacking"}},{"kind":"Field","name":{"kind":"Name","value":"displayNsfw"}},{"kind":"Field","name":{"kind":"Name","value":"disableVideos"}},{"kind":"Field","name":{"kind":"Name","value":"persistQueries"}},{"kind":"Field","name":{"kind":"Name","value":"disableReviews"}},{"kind":"Field","name":{"kind":"Name","value":"disableIntegrations"}},{"kind":"Field","name":{"kind":"Name","value":"disableWatchProviders"}},{"kind":"Field","name":{"kind":"Name","value":"disableNavigationAnimation"}},{"kind":"Field","name":{"kind":"Name","value":"dashboard"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"section"}},{"kind":"Field","name":{"kind":"Name","value":"hidden"}},{"kind":"Field","name":{"kind":"Name","value":"numElements"}}]}},{"kind":"Field","name":{"kind":"Name","value":"watchProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"values"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fitness"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"logging"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"showDetailsWhileEditing"}}]}},{"kind":"Field","name":{"kind":"Name","value":"exercises"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"unitSystem"}},{"kind":"Field","name":{"kind":"Name","value":"setRestTimers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SetRestTimersPart"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"measurements"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"custom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"dataType"}}]}},{"kind":"Field","name":{"kind":"Name","value":"inbuilt"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"bodyMassIndex"}},{"kind":"Field","name":{"kind":"Name","value":"totalBodyWater"}},{"kind":"Field","name":{"kind":"Name","value":"muscle"}},{"kind":"Field","name":{"kind":"Name","value":"leanBodyMass"}},{"kind":"Field","name":{"kind":"Name","value":"bodyFat"}},{"kind":"Field","name":{"kind":"Name","value":"boneMass"}},{"kind":"Field","name":{"kind":"Name","value":"visceralFat"}},{"kind":"Field","name":{"kind":"Name","value":"waistCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"waistToHeightRatio"}},{"kind":"Field","name":{"kind":"Name","value":"hipCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"waistToHipRatio"}},{"kind":"Field","name":{"kind":"Name","value":"chestCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"thighCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"bicepsCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"neckCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"bodyFatCaliper"}},{"kind":"Field","name":{"kind":"Name","value":"chestSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"abdominalSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"thighSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"basalMetabolicRate"}},{"kind":"Field","name":{"kind":"Name","value":"totalDailyEnergyExpenditure"}},{"kind":"Field","name":{"kind":"Name","value":"calories"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"notifications"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"toSend"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}}]}},{"kind":"Field","name":{"kind":"Name","value":"featuresEnabled"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"others"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"calendar"}},{"kind":"Field","name":{"kind":"Name","value":"collections"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fitness"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"workouts"}},{"kind":"Field","name":{"kind":"Name","value":"templates"}},{"kind":"Field","name":{"kind":"Name","value":"measurements"}}]}},{"kind":"Field","name":{"kind":"Name","value":"media"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"anime"}},{"kind":"Field","name":{"kind":"Name","value":"audioBook"}},{"kind":"Field","name":{"kind":"Name","value":"book"}},{"kind":"Field","name":{"kind":"Name","value":"manga"}},{"kind":"Field","name":{"kind":"Name","value":"movie"}},{"kind":"Field","name":{"kind":"Name","value":"podcast"}},{"kind":"Field","name":{"kind":"Name","value":"show"}},{"kind":"Field","name":{"kind":"Name","value":"videoGame"}},{"kind":"Field","name":{"kind":"Name","value":"visualNovel"}},{"kind":"Field","name":{"kind":"Name","value":"people"}},{"kind":"Field","name":{"kind":"Name","value":"groups"}},{"kind":"Field","name":{"kind":"Name","value":"genres"}}]}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SetRestTimersPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SetRestTimersSettings"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"drop"}},{"kind":"Field","name":{"kind":"Name","value":"warmup"}},{"kind":"Field","name":{"kind":"Name","value":"normal"}},{"kind":"Field","name":{"kind":"Name","value":"failure"}}]}}]} as unknown as DocumentNode<UserDetailsQuery, UserDetailsQueryVariables>;
+export const UserDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserDetails"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userDetails"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"isDisabled"}},{"kind":"Field","name":{"kind":"Name","value":"oidcIssuerId"}},{"kind":"Field","name":{"kind":"Name","value":"preferences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"general"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"reviewScale"}},{"kind":"Field","name":{"kind":"Name","value":"gridPacking"}},{"kind":"Field","name":{"kind":"Name","value":"displayNsfw"}},{"kind":"Field","name":{"kind":"Name","value":"disableVideos"}},{"kind":"Field","name":{"kind":"Name","value":"persistQueries"}},{"kind":"Field","name":{"kind":"Name","value":"disableReviews"}},{"kind":"Field","name":{"kind":"Name","value":"disableIntegrations"}},{"kind":"Field","name":{"kind":"Name","value":"disableWatchProviders"}},{"kind":"Field","name":{"kind":"Name","value":"disableNavigationAnimation"}},{"kind":"Field","name":{"kind":"Name","value":"dashboard"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hidden"}},{"kind":"Field","name":{"kind":"Name","value":"section"}},{"kind":"Field","name":{"kind":"Name","value":"numElements"}},{"kind":"Field","name":{"kind":"Name","value":"deduplicateMedia"}}]}},{"kind":"Field","name":{"kind":"Name","value":"watchProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"values"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fitness"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"logging"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"showDetailsWhileEditing"}}]}},{"kind":"Field","name":{"kind":"Name","value":"exercises"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"unitSystem"}},{"kind":"Field","name":{"kind":"Name","value":"setRestTimers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SetRestTimersPart"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"measurements"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"custom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"dataType"}}]}},{"kind":"Field","name":{"kind":"Name","value":"inbuilt"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"bodyMassIndex"}},{"kind":"Field","name":{"kind":"Name","value":"totalBodyWater"}},{"kind":"Field","name":{"kind":"Name","value":"muscle"}},{"kind":"Field","name":{"kind":"Name","value":"leanBodyMass"}},{"kind":"Field","name":{"kind":"Name","value":"bodyFat"}},{"kind":"Field","name":{"kind":"Name","value":"boneMass"}},{"kind":"Field","name":{"kind":"Name","value":"visceralFat"}},{"kind":"Field","name":{"kind":"Name","value":"waistCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"waistToHeightRatio"}},{"kind":"Field","name":{"kind":"Name","value":"hipCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"waistToHipRatio"}},{"kind":"Field","name":{"kind":"Name","value":"chestCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"thighCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"bicepsCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"neckCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"bodyFatCaliper"}},{"kind":"Field","name":{"kind":"Name","value":"chestSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"abdominalSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"thighSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"basalMetabolicRate"}},{"kind":"Field","name":{"kind":"Name","value":"totalDailyEnergyExpenditure"}},{"kind":"Field","name":{"kind":"Name","value":"calories"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"notifications"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"toSend"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}}]}},{"kind":"Field","name":{"kind":"Name","value":"featuresEnabled"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"others"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"calendar"}},{"kind":"Field","name":{"kind":"Name","value":"collections"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fitness"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"workouts"}},{"kind":"Field","name":{"kind":"Name","value":"templates"}},{"kind":"Field","name":{"kind":"Name","value":"measurements"}}]}},{"kind":"Field","name":{"kind":"Name","value":"media"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"anime"}},{"kind":"Field","name":{"kind":"Name","value":"audioBook"}},{"kind":"Field","name":{"kind":"Name","value":"book"}},{"kind":"Field","name":{"kind":"Name","value":"manga"}},{"kind":"Field","name":{"kind":"Name","value":"movie"}},{"kind":"Field","name":{"kind":"Name","value":"podcast"}},{"kind":"Field","name":{"kind":"Name","value":"show"}},{"kind":"Field","name":{"kind":"Name","value":"videoGame"}},{"kind":"Field","name":{"kind":"Name","value":"visualNovel"}},{"kind":"Field","name":{"kind":"Name","value":"people"}},{"kind":"Field","name":{"kind":"Name","value":"groups"}},{"kind":"Field","name":{"kind":"Name","value":"genres"}}]}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SetRestTimersPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SetRestTimersSettings"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"drop"}},{"kind":"Field","name":{"kind":"Name","value":"warmup"}},{"kind":"Field","name":{"kind":"Name","value":"normal"}},{"kind":"Field","name":{"kind":"Name","value":"failure"}}]}}]} as unknown as DocumentNode<UserDetailsQuery, UserDetailsQueryVariables>;
 export const UserExerciseDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserExerciseDetails"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"exerciseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userExerciseDetails"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"exerciseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"exerciseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"collections"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CollectionPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"reviews"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ReviewItemPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"history"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"idx"}},{"kind":"Field","name":{"kind":"Name","value":"workoutId"}},{"kind":"Field","name":{"kind":"Name","value":"workoutEndOn"}},{"kind":"Field","name":{"kind":"Name","value":"bestSet"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutSetRecordPart"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"exerciseId"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"lastUpdatedOn"}},{"kind":"Field","name":{"kind":"Name","value":"exerciseNumTimesInteracted"}},{"kind":"Field","name":{"kind":"Name","value":"exerciseExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"settings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setRestTimers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SetRestTimersPart"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"lifetimeStats"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"reps"}},{"kind":"Field","name":{"kind":"Name","value":"distance"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"personalBestsAchieved"}}]}},{"kind":"Field","name":{"kind":"Name","value":"personalBests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"sets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workoutId"}},{"kind":"Field","name":{"kind":"Name","value":"exerciseIdx"}},{"kind":"Field","name":{"kind":"Name","value":"setIdx"}}]}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenShowExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenShowExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}},{"kind":"Field","name":{"kind":"Name","value":"season"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenPodcastExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenAnimeExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenMangaExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"volume"}},{"kind":"Field","name":{"kind":"Name","value":"chapter"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkoutSetStatisticPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkoutSetStatistic"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"reps"}},{"kind":"Field","name":{"kind":"Name","value":"pace"}},{"kind":"Field","name":{"kind":"Name","value":"oneRm"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"volume"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"distance"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CollectionPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Collection"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"userId"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ReviewItemPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ReviewItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"rating"}},{"kind":"Field","name":{"kind":"Name","value":"postedOn"}},{"kind":"Field","name":{"kind":"Name","value":"isSpoiler"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"textOriginal"}},{"kind":"Field","name":{"kind":"Name","value":"textRendered"}},{"kind":"Field","name":{"kind":"Name","value":"seenItemsAssociatedWith"}},{"kind":"Field","name":{"kind":"Name","value":"postedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"text"}},{"kind":"Field","name":{"kind":"Name","value":"likedBy"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"showExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenShowExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"animeExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"mangaExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkoutSetRecordPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkoutSetRecord"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"personalBests"}},{"kind":"Field","name":{"kind":"Name","value":"statistic"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutSetStatisticPart"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SetRestTimersPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SetRestTimersSettings"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"drop"}},{"kind":"Field","name":{"kind":"Name","value":"warmup"}},{"kind":"Field","name":{"kind":"Name","value":"normal"}},{"kind":"Field","name":{"kind":"Name","value":"failure"}}]}}]} as unknown as DocumentNode<UserExerciseDetailsQuery, UserExerciseDetailsQueryVariables>;
 export const UserMeasurementsListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserMeasurementsList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UserMeasurementsListInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userMeasurementsList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"stats"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"bodyMassIndex"}},{"kind":"Field","name":{"kind":"Name","value":"totalBodyWater"}},{"kind":"Field","name":{"kind":"Name","value":"muscle"}},{"kind":"Field","name":{"kind":"Name","value":"leanBodyMass"}},{"kind":"Field","name":{"kind":"Name","value":"bodyFat"}},{"kind":"Field","name":{"kind":"Name","value":"boneMass"}},{"kind":"Field","name":{"kind":"Name","value":"visceralFat"}},{"kind":"Field","name":{"kind":"Name","value":"waistCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"waistToHeightRatio"}},{"kind":"Field","name":{"kind":"Name","value":"hipCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"waistToHipRatio"}},{"kind":"Field","name":{"kind":"Name","value":"chestCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"thighCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"bicepsCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"neckCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"bodyFatCaliper"}},{"kind":"Field","name":{"kind":"Name","value":"chestSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"abdominalSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"thighSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"basalMetabolicRate"}},{"kind":"Field","name":{"kind":"Name","value":"totalDailyEnergyExpenditure"}},{"kind":"Field","name":{"kind":"Name","value":"calories"}},{"kind":"Field","name":{"kind":"Name","value":"custom"}}]}}]}}]}}]} as unknown as DocumentNode<UserMeasurementsListQuery, UserMeasurementsListQueryVariables>;
 export const UserMetadataDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserMetadataDetails"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"metadataId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userMetadataDetails"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"metadataId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"metadataId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"mediaReason"}},{"kind":"Field","name":{"kind":"Name","value":"hasInteracted"}},{"kind":"Field","name":{"kind":"Name","value":"collections"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CollectionPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"inProgress"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"history"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"averageRating"}},{"kind":"Field","name":{"kind":"Name","value":"reviews"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ReviewItemPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"seenByAllCount"}},{"kind":"Field","name":{"kind":"Name","value":"seenByUserCount"}},{"kind":"Field","name":{"kind":"Name","value":"nextEntry"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"season"}},{"kind":"Field","name":{"kind":"Name","value":"volume"}},{"kind":"Field","name":{"kind":"Name","value":"episode"}},{"kind":"Field","name":{"kind":"Name","value":"chapter"}}]}},{"kind":"Field","name":{"kind":"Name","value":"showProgress"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"timesSeen"}},{"kind":"Field","name":{"kind":"Name","value":"seasonNumber"}},{"kind":"Field","name":{"kind":"Name","value":"episodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episodeNumber"}},{"kind":"Field","name":{"kind":"Name","value":"timesSeen"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastProgress"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episodeNumber"}},{"kind":"Field","name":{"kind":"Name","value":"timesSeen"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenShowExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenShowExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}},{"kind":"Field","name":{"kind":"Name","value":"season"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenPodcastExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenAnimeExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenMangaExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"volume"}},{"kind":"Field","name":{"kind":"Name","value":"chapter"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CollectionPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Collection"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"userId"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Seen"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"progress"}},{"kind":"Field","name":{"kind":"Name","value":"reviewId"}},{"kind":"Field","name":{"kind":"Name","value":"startedOn"}},{"kind":"Field","name":{"kind":"Name","value":"finishedOn"}},{"kind":"Field","name":{"kind":"Name","value":"lastUpdatedOn"}},{"kind":"Field","name":{"kind":"Name","value":"manualTimeSpent"}},{"kind":"Field","name":{"kind":"Name","value":"numTimesUpdated"}},{"kind":"Field","name":{"kind":"Name","value":"providerWatchedOn"}},{"kind":"Field","name":{"kind":"Name","value":"showExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenShowExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"animeExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"mangaExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ReviewItemPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ReviewItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"rating"}},{"kind":"Field","name":{"kind":"Name","value":"postedOn"}},{"kind":"Field","name":{"kind":"Name","value":"isSpoiler"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"textOriginal"}},{"kind":"Field","name":{"kind":"Name","value":"textRendered"}},{"kind":"Field","name":{"kind":"Name","value":"seenItemsAssociatedWith"}},{"kind":"Field","name":{"kind":"Name","value":"postedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"text"}},{"kind":"Field","name":{"kind":"Name","value":"likedBy"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"showExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenShowExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"animeExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"mangaExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"}}]}}]}}]} as unknown as DocumentNode<UserMetadataDetailsQuery, UserMetadataDetailsQueryVariables>;
diff --git a/libs/graphql/src/backend/queries/UserDetails.gql b/libs/graphql/src/backend/queries/UserDetails.gql
index 9f5ec4ea9a..5bfa0aafe1 100644
--- a/libs/graphql/src/backend/queries/UserDetails.gql
+++ b/libs/graphql/src/backend/queries/UserDetails.gql
@@ -19,9 +19,10 @@ query UserDetails {
 					disableWatchProviders
 					disableNavigationAnimation
 					dashboard {
-						section
 						hidden
+						section
 						numElements
+						deduplicateMedia
 					}
 					watchProviders {
 						lot
diff --git a/libs/transactional/package.json b/libs/transactional/package.json
index 7fad87fb1a..643679736a 100644
--- a/libs/transactional/package.json
+++ b/libs/transactional/package.json
@@ -2,7 +2,7 @@
 	"name": "@ryot/transactional",
 	"private": true,
 	"dependencies": {
-		"@react-email/components": "0.0.22",
+		"@react-email/components": "0.0.26",
 		"@ryot/ts-utils": "workspace:*",
 		"react": "18.3.1",
 		"react-dom": "18.3.1",
diff --git a/yarn.lock b/yarn.lock
index d0176b9861..5494fa42a0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5310,41 +5310,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/body@npm:0.0.9":
-  version: 0.0.9
-  resolution: "@react-email/body@npm:0.0.9"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/87caa8938a07d895bcbada50c31fd6f9c595e3ccdea09fdfe31e3e8939f9a5f5668ade6726257cb5d26e48aa3857b6d16bc1d12e4a7cbac7ed45fa866eeff258
-  languageName: node
-  linkType: hard
-
-"@react-email/button@npm:0.0.16":
-  version: 0.0.16
-  resolution: "@react-email/button@npm:0.0.16"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/1f754bbe6de1c82dd95b69748c32406ae8346d01e8d51832468c7dacca7e2fff153c18043354a4c350cf3ea53d96d991f3da59cd46dfdc52ebb18b029935c78f
-  languageName: node
-  linkType: hard
-
-"@react-email/button@npm:0.0.17":
-  version: 0.0.17
-  resolution: "@react-email/button@npm:0.0.17"
+"@react-email/button@npm:0.0.18":
+  version: 0.0.18
+  resolution: "@react-email/button@npm:0.0.18"
   peerDependencies:
     react: ^18.0 || ^19.0 || ^19.0.0-rc
-  checksum: 10/9fab2e3d4ba39990816c49d3265ff89598cc804f6e3d1e85afaf5264657d1ead6acf88e0ad0991ece8d685c1722179d1d4a6274168548c0a765cb7b2519896af
-  languageName: node
-  linkType: hard
-
-"@react-email/code-block@npm:0.0.6":
-  version: 0.0.6
-  resolution: "@react-email/code-block@npm:0.0.6"
-  dependencies:
-    prismjs: "npm:1.29.0"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/6d014fa693f2174e4cbcb24a59a2c5346d0c9d4db98968df665d5388838543bc085cabff1167100d710c20bda64ae9a7c0198c8ffbeced42dcb82f523219b39a
+  checksum: 10/1f4c37a7d337d6b234467ff097c2d86df703816f669b4ba135a5892095659b8c40d995b34fa9aa357eedc8578daf2509b5bbcfa4b594b05c9faa50c9d26c9eba
   languageName: node
   linkType: hard
 
@@ -5359,15 +5330,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/code-inline@npm:0.0.3":
-  version: 0.0.3
-  resolution: "@react-email/code-inline@npm:0.0.3"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/e29f83f2f7771075a5d04246f47b30844b2c7cd4b7097e4d04d90e53fc71356b55cd94e4ebf53c399c87d9cdfe62528a734e22e61e98e83c9102724b4e376f37
-  languageName: node
-  linkType: hard
-
 "@react-email/code-inline@npm:0.0.4":
   version: 0.0.4
   resolution: "@react-email/code-inline@npm:0.0.4"
@@ -5377,15 +5339,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/column@npm:0.0.11":
-  version: 0.0.11
-  resolution: "@react-email/column@npm:0.0.11"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/a7b1b0fba17869e9151a88e95d2732a8aac89bfaa8447ce5a8eb5e942f1586e664012a04cb42ab32c42a52b60a6b246edf3e6ef182007da2804a325d0571c831
-  languageName: node
-  linkType: hard
-
 "@react-email/column@npm:0.0.12":
   version: 0.0.12
   resolution: "@react-email/column@npm:0.0.12"
@@ -5395,42 +5348,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/components@npm:0.0.22":
-  version: 0.0.22
-  resolution: "@react-email/components@npm:0.0.22"
-  dependencies:
-    "@react-email/body": "npm:0.0.9"
-    "@react-email/button": "npm:0.0.16"
-    "@react-email/code-block": "npm:0.0.6"
-    "@react-email/code-inline": "npm:0.0.3"
-    "@react-email/column": "npm:0.0.11"
-    "@react-email/container": "npm:0.0.13"
-    "@react-email/font": "npm:0.0.7"
-    "@react-email/head": "npm:0.0.10"
-    "@react-email/heading": "npm:0.0.13"
-    "@react-email/hr": "npm:0.0.9"
-    "@react-email/html": "npm:0.0.9"
-    "@react-email/img": "npm:0.0.9"
-    "@react-email/link": "npm:0.0.9"
-    "@react-email/markdown": "npm:0.0.11"
-    "@react-email/preview": "npm:0.0.10"
-    "@react-email/render": "npm:0.0.17"
-    "@react-email/row": "npm:0.0.9"
-    "@react-email/section": "npm:0.0.13"
-    "@react-email/tailwind": "npm:0.0.19"
-    "@react-email/text": "npm:0.0.9"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/93bc3cd2ddd9a153d79d4a0da4886dd79c55129cdbda148ed16f25e714c515b7377978a92fa2aaf1ac1cf81a897b648137ce232288e2c3585201124121a0fba0
-  languageName: node
-  linkType: hard
-
-"@react-email/components@npm:0.0.25":
-  version: 0.0.25
-  resolution: "@react-email/components@npm:0.0.25"
+"@react-email/components@npm:0.0.26":
+  version: 0.0.26
+  resolution: "@react-email/components@npm:0.0.26"
   dependencies:
     "@react-email/body": "npm:0.0.10"
-    "@react-email/button": "npm:0.0.17"
+    "@react-email/button": "npm:0.0.18"
     "@react-email/code-block": "npm:0.0.9"
     "@react-email/code-inline": "npm:0.0.4"
     "@react-email/column": "npm:0.0.12"
@@ -5441,26 +5364,17 @@ __metadata:
     "@react-email/hr": "npm:0.0.10"
     "@react-email/html": "npm:0.0.10"
     "@react-email/img": "npm:0.0.10"
-    "@react-email/link": "npm:0.0.10"
+    "@react-email/link": "npm:0.0.11"
     "@react-email/markdown": "npm:0.0.12"
     "@react-email/preview": "npm:0.0.11"
-    "@react-email/render": "npm:1.0.1"
-    "@react-email/row": "npm:0.0.10"
-    "@react-email/section": "npm:0.0.14"
-    "@react-email/tailwind": "npm:0.1.0"
+    "@react-email/render": "npm:1.0.2"
+    "@react-email/row": "npm:0.0.11"
+    "@react-email/section": "npm:0.0.15"
+    "@react-email/tailwind": "npm:1.0.0"
     "@react-email/text": "npm:0.0.10"
   peerDependencies:
     react: ^18.0 || ^19.0 || ^19.0.0-rc
-  checksum: 10/e4fbefc1883043d375b53ffab7d8ebc93f605ac227203256535701592c819be69c4fbfc637c85ebfacc897b0ae0f2f0183049acdb4674233dd8049e7d9eba09c
-  languageName: node
-  linkType: hard
-
-"@react-email/container@npm:0.0.13":
-  version: 0.0.13
-  resolution: "@react-email/container@npm:0.0.13"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/9f4b679d8deda2c7d976666688c9d9ecf17f61b15bbd4b3c4192742a171b97d170c52fc8a0039f203ec0ff83516756af3648a339a705afd58fa9bbfaa3c80683
+  checksum: 10/202d29ad4e4f016e8b51ea089e7642d7bfd30ea7c87f434b7bda4ed555f1d1280787da77d2880205a0c71d1667fb38a5e94250cc82d2e30400f1637c5aa2cc1b
   languageName: node
   linkType: hard
 
@@ -5473,15 +5387,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/font@npm:0.0.7":
-  version: 0.0.7
-  resolution: "@react-email/font@npm:0.0.7"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/63728aee9a862484b9045abe3235c93c9cdd85bbaa062b22f84640c66e83bf401702623b4810ab74a4422566e6751d935985594c59a58b6bfe67a8619680ff11
-  languageName: node
-  linkType: hard
-
 "@react-email/font@npm:0.0.8":
   version: 0.0.8
   resolution: "@react-email/font@npm:0.0.8"
@@ -5491,15 +5396,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/head@npm:0.0.10":
-  version: 0.0.10
-  resolution: "@react-email/head@npm:0.0.10"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/62a7062d76fd849e8d50f253dc70674f8d49523c11aab575f4486eec6e2104dc4d74a601093d8dacfec7c11a09c6441251206c08bb3ad8f3f728d65e92e3703f
-  languageName: node
-  linkType: hard
-
 "@react-email/head@npm:0.0.11":
   version: 0.0.11
   resolution: "@react-email/head@npm:0.0.11"
@@ -5509,17 +5405,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/heading@npm:0.0.13":
-  version: 0.0.13
-  resolution: "@react-email/heading@npm:0.0.13"
-  dependencies:
-    "@radix-ui/react-slot": "npm:1.1.0"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/c2809ed42028eb8e7d1ea07c169f3cfe1d18a571532ceb0293d21b4ad8fd52b78513122b1f024e1d4fc6b2cb72d5654f20fefa4def016501dfdb7a60280a1c53
-  languageName: node
-  linkType: hard
-
 "@react-email/heading@npm:0.0.14":
   version: 0.0.14
   resolution: "@react-email/heading@npm:0.0.14"
@@ -5538,15 +5423,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/hr@npm:0.0.9":
-  version: 0.0.9
-  resolution: "@react-email/hr@npm:0.0.9"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/2e1a693480a01a076c1fbcda87c617791083125e7d0e0afd6daccf3daff8116c851b3a2d0a4d48179ff65af26d90e859eb5142b5d307057cf9254806486d6c72
-  languageName: node
-  linkType: hard
-
 "@react-email/html@npm:0.0.10":
   version: 0.0.10
   resolution: "@react-email/html@npm:0.0.10"
@@ -5556,15 +5432,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/html@npm:0.0.9":
-  version: 0.0.9
-  resolution: "@react-email/html@npm:0.0.9"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/c572a4fb54da865b5023f140b215f9d2829d1b3aedd45bd1053e71cdf7a53c99cd27ea826e83fda158eddee1b63e5e2589e2c218c808f88e78204459a8048a5f
-  languageName: node
-  linkType: hard
-
 "@react-email/img@npm:0.0.10":
   version: 0.0.10
   resolution: "@react-email/img@npm:0.0.10"
@@ -5574,41 +5441,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/img@npm:0.0.9":
-  version: 0.0.9
-  resolution: "@react-email/img@npm:0.0.9"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/3bfdf701b4f4e6421269129bd2a8a0d0ecba23c41114e50d48aeeabb801a718665268e7635cdde2e9a48c4eb571d9a30227c7956052ef584171ada8650f4dcc9
-  languageName: node
-  linkType: hard
-
-"@react-email/link@npm:0.0.10":
-  version: 0.0.10
-  resolution: "@react-email/link@npm:0.0.10"
-  peerDependencies:
-    react: ^18.0 || ^19.0 || ^19.0.0-rc
-  checksum: 10/153a0013622c8912418267f32c28a6194ea4ecdd12251057a5e221a45faccb11fdfcfef54949f84841fbcbe1e79e3ad7f45d8695172b5e0d250a7bd148c35e06
-  languageName: node
-  linkType: hard
-
-"@react-email/link@npm:0.0.9":
-  version: 0.0.9
-  resolution: "@react-email/link@npm:0.0.9"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/c1f1cdcbdaa6c9b763d48982977175a918ce573300be1216e701ca668ceafd77433a5a7f6c6d7d046915f411572db87530f1b3b051ec80473f740e6655496f34
-  languageName: node
-  linkType: hard
-
-"@react-email/markdown@npm:0.0.11":
+"@react-email/link@npm:0.0.11":
   version: 0.0.11
-  resolution: "@react-email/markdown@npm:0.0.11"
-  dependencies:
-    md-to-react-email: "npm:5.0.2"
+  resolution: "@react-email/link@npm:0.0.11"
   peerDependencies:
-    react: ^18.2.0
-  checksum: 10/5cb0ca89a7a30b078ebf2fac7394b9f25a9c7e8a167f1d790892268de006719b458daf3ffccf8b4fc1296d7b243b34c1e7fde9768aeaabba0858715b0472ef2e
+    react: ^18.0 || ^19.0 || ^19.0.0-rc
+  checksum: 10/ce858b4ee11fd88bf9e12a9705490b1869b10f7da1e7052b806a5bad087f2c0a0958af6168eaca8eeeefbec2409543e548b59a4e123dd2812b8a2bccc64bb0a8
   languageName: node
   linkType: hard
 
@@ -5623,15 +5461,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/preview@npm:0.0.10":
-  version: 0.0.10
-  resolution: "@react-email/preview@npm:0.0.10"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/a7c960bf9054c3e9b2c6ab88dedfde55cbbb0714b8080fa308cd726a347bb48a71ae1ed22b3d7b29d869fe7ae6deadf20c5a01ca74ca3ad60729b1a42ce1efce
-  languageName: node
-  linkType: hard
-
 "@react-email/preview@npm:0.0.11":
   version: 0.0.11
   resolution: "@react-email/preview@npm:0.0.11"
@@ -5641,23 +5470,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/render@npm:0.0.17":
-  version: 0.0.17
-  resolution: "@react-email/render@npm:0.0.17"
-  dependencies:
-    html-to-text: "npm:9.0.5"
-    js-beautify: "npm:^1.14.11"
-    react-promise-suspense: "npm:0.3.4"
-  peerDependencies:
-    react: ^18.2.0
-    react-dom: ^18.2.0
-  checksum: 10/39c2be62e2dcccbba39a13c2551dadfd99aa72429320c32a8c7d7c94ccbd56a791489b4bf336ef44e8828731eb2f555213cad963d55d878cd80d575f909d4b2e
-  languageName: node
-  linkType: hard
-
-"@react-email/render@npm:1.0.1":
-  version: 1.0.1
-  resolution: "@react-email/render@npm:1.0.1"
+"@react-email/render@npm:1.0.2":
+  version: 1.0.2
+  resolution: "@react-email/render@npm:1.0.2"
   dependencies:
     html-to-text: "npm:9.0.5"
     js-beautify: "npm:^1.14.11"
@@ -5665,61 +5480,34 @@ __metadata:
   peerDependencies:
     react: ^18.0 || ^19.0 || ^19.0.0-rc
     react-dom: ^18.0 || ^19.0 || ^19.0.0-rc
-  checksum: 10/0ddc28a8a523802c34f4fe0e69de93c0d495ba05357a7061bee1ea34e29a4c17a4bba82569568b920006d17a2e67689b9b1cb41b106e684b826ed7017d49b4d2
+  checksum: 10/f2fc9f579c95e14d1bb721c46eb37473ff7989d895a05fce72c611d2c0eae21365f9bc0463d7f88feb99af2c9c163f3e3a8a3f597fdb74c5f53ea536dbb4a480
   languageName: node
   linkType: hard
 
-"@react-email/row@npm:0.0.10":
-  version: 0.0.10
-  resolution: "@react-email/row@npm:0.0.10"
+"@react-email/row@npm:0.0.11":
+  version: 0.0.11
+  resolution: "@react-email/row@npm:0.0.11"
   peerDependencies:
     react: ^18.0 || ^19.0 || ^19.0.0-rc
-  checksum: 10/23288ca36b992e30ff1bc34320da3bbf40782e84b4201f5e4c3dba6176f29c3225b7f0062122a5577bb52eacfadc5ca9fd18ee465b1ab67400c1277300dff111
-  languageName: node
-  linkType: hard
-
-"@react-email/row@npm:0.0.9":
-  version: 0.0.9
-  resolution: "@react-email/row@npm:0.0.9"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/8c3cb6d358bed02e31ce205b367d8a79034296935c150150033885efb485c10fb202765e371ff53b41fe08f8411dd5e0c1fa677176146666847a91fdaabdcd33
+  checksum: 10/aac3942f47758fc7c8a264dde4a6026719cb09ff22d512d7185740a868d98d7ce0322efa77a9b68811d22b149897fce9fb89f349083718c34e6a7ebb750db97a
   languageName: node
   linkType: hard
 
-"@react-email/section@npm:0.0.13":
-  version: 0.0.13
-  resolution: "@react-email/section@npm:0.0.13"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/44b1a3b6575654a8f3559823dbe342c39187f7618e0469f368c4d783b642eca25fc1ad272bc76b9bb8bec1559819c621f96eea951ae4019d122c81a5d1fbe18c
-  languageName: node
-  linkType: hard
-
-"@react-email/section@npm:0.0.14":
-  version: 0.0.14
-  resolution: "@react-email/section@npm:0.0.14"
+"@react-email/section@npm:0.0.15":
+  version: 0.0.15
+  resolution: "@react-email/section@npm:0.0.15"
   peerDependencies:
     react: ^18.0 || ^19.0 || ^19.0.0-rc
-  checksum: 10/c18a1d47a4dadb49fd48ac004127f40247a0d28b523aea1e610c3d73439c2c00bd582b3c56aa6fec292acba97a431beea29292766950e58cbf0d13cb32d4bb2a
+  checksum: 10/ff8e7d81c3cc825c17daa25717cd952f7d26fb0657df1f4edb1f8feca10229d5188ad2f1c4df4179cf4381d21c75221d7d6f66e86ddf1d7ba049986c556d11e0
   languageName: node
   linkType: hard
 
-"@react-email/tailwind@npm:0.0.19":
-  version: 0.0.19
-  resolution: "@react-email/tailwind@npm:0.0.19"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/ecdb4db3ac0915db89c615274557f51f14ed43b6bb89e3813255a5b993506e9e236a9faf0aea7f6910cc8c187b5889dd6c09663a97664d08c953fc1e8ad74e4c
-  languageName: node
-  linkType: hard
-
-"@react-email/tailwind@npm:0.1.0":
-  version: 0.1.0
-  resolution: "@react-email/tailwind@npm:0.1.0"
+"@react-email/tailwind@npm:1.0.0":
+  version: 1.0.0
+  resolution: "@react-email/tailwind@npm:1.0.0"
   peerDependencies:
     react: ^18.0 || ^19.0 || ^19.0.0-rc
-  checksum: 10/3e002b23e0c72d6e27b8be9c640e7b7392aec651b6bc50a8a92064d398e66615b1a1647f4641302f7e1949a7d7878c88c8f3b4b98f295b0882875b4a097f2122
+  checksum: 10/4a6fcee22cbe380af42ae3bb8ac91415d4e385d047423eae38abc74ba0597c81edc3c52caf5a036b5bbcd12814e1158460104ccb19c95b7e04c25762f3d3e7b0
   languageName: node
   linkType: hard
 
@@ -5732,15 +5520,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@react-email/text@npm:0.0.9":
-  version: 0.0.9
-  resolution: "@react-email/text@npm:0.0.9"
-  peerDependencies:
-    react: ^18.2.0
-  checksum: 10/1ccd85815e3f79970927a2fc7712e6b229b2bd5f0ad16b14fb347d113354a12d5f0b7e87a6889f8ecc115ce1d11b6c6ce08173c180a9ef963afdffde6e3eda0a
-  languageName: node
-  linkType: hard
-
 "@remix-pwa/dev@npm:3.1.0":
   version: 3.1.0
   resolution: "@remix-pwa/dev@npm:3.1.0"
@@ -6254,7 +6033,7 @@ __metadata:
     "@ryot/generated": "workspace:*"
     "@ryot/graphql": "workspace:*"
     "@ryot/ts-utils": "workspace:*"
-    "@tabler/icons-react": "npm:3.21.0"
+    "@tabler/icons-react": "npm:3.17.0"
     "@tanstack/react-query": "npm:5.59.16"
     "@tanstack/react-query-devtools": "npm:5.59.16"
     "@types/cookie": "npm:1.0.0"
@@ -6290,13 +6069,13 @@ __metadata:
     react-dom: "npm:18.3.1"
     react-virtuoso: "npm:4.12.0"
     react-webcam: "npm:7.2.0"
-    recharts: "npm:2.13.1"
-    remix-development-tools: "npm:4.7.3"
+    recharts: "npm:2.13.3"
+    remix-development-tools: "npm:4.7.5"
     remix-routes: "npm:1.7.7"
     remix-utils: "npm:7.7.0"
     tailwind-merge: "npm:2.5.4"
     tiny-invariant: "npm:1.3.3"
-    ts-essentials: "npm:10.0.2"
+    ts-essentials: "npm:10.0.3"
     ts-pattern: "npm:5.5.0"
     typescript: "npm:5.6.3"
     typescript-plugin-css-modules: "npm:5.1.0"
@@ -6345,7 +6124,7 @@ __metadata:
   version: 0.0.0-use.local
   resolution: "@ryot/transactional@workspace:libs/transactional"
   dependencies:
-    "@react-email/components": "npm:0.0.22"
+    "@react-email/components": "npm:0.0.26"
     "@ryot/ts-utils": "workspace:*"
     "@types/react": "npm:18.3.12"
     "@types/react-dom": "npm:18.3.1"
@@ -6382,7 +6161,7 @@ __metadata:
     "@radix-ui/react-label": "npm:2.1.0"
     "@radix-ui/react-slot": "npm:1.1.0"
     "@radix-ui/react-tooltip": "npm:1.1.3"
-    "@react-email/components": "npm:0.0.25"
+    "@react-email/components": "npm:0.0.26"
     "@remix-run/dev": "npm:2.13.1"
     "@remix-run/node": "npm:2.13.1"
     "@remix-run/react": "npm:2.13.1"
@@ -6391,7 +6170,7 @@ __metadata:
     "@ryot/graphql": "workspace:*"
     "@ryot/transactional": "workspace:*"
     "@ryot/ts-utils": "workspace:*"
-    "@tabler/icons-react": "npm:3.21.0"
+    "@tabler/icons-react": "npm:3.17.0"
     "@tailwindcss/typography": "npm:0.5.15"
     "@types/crypto-js": "npm:^4.2.2"
     "@types/lodash": "npm:4.17.13"
@@ -6411,7 +6190,7 @@ __metadata:
     graphql: "npm:16.9.0"
     graphql-request: "npm:7.1.0"
     humanize-duration-ts: "npm:2.1.1"
-    input-otp: "npm:1.2.5"
+    input-otp: "npm:1.4.0"
     isbot: "npm:5.1.17"
     lodash: "npm:4.17.21"
     lucide-react: "npm:0.454.0"
@@ -6599,21 +6378,21 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@tabler/icons-react@npm:3.21.0":
-  version: 3.21.0
-  resolution: "@tabler/icons-react@npm:3.21.0"
+"@tabler/icons-react@npm:3.17.0":
+  version: 3.17.0
+  resolution: "@tabler/icons-react@npm:3.17.0"
   dependencies:
-    "@tabler/icons": "npm:3.21.0"
+    "@tabler/icons": "npm:3.17.0"
   peerDependencies:
     react: ">= 16"
-  checksum: 10/d168b49f7877733b70af05793d3c6c552b2fecd4d8f95454afa2d9334f8382728270031e722470eb8d18fc6c51a00481ca54599ee49ec1cac0eae9fb3dded413
+  checksum: 10/41b85f424202ae7ef95969c689688f96192066f9587e253817d392695be19d9b65a673947ef580a0912784735281d96686ce3e3c95885f13ba21e18a461baca4
   languageName: node
   linkType: hard
 
-"@tabler/icons@npm:3.21.0":
-  version: 3.21.0
-  resolution: "@tabler/icons@npm:3.21.0"
-  checksum: 10/52e6c46819dc115cbb73e22966fe394b42f7f9a2a83198228e07442b6726703507c327c4d326720ae47bab895c876f9d7be782685c39e885d315414129f9adb2
+"@tabler/icons@npm:3.17.0":
+  version: 3.17.0
+  resolution: "@tabler/icons@npm:3.17.0"
+  checksum: 10/b566234a4c4bde5c91f55411066dc7abfc3f102eb447951e17e96f3d7849f07eca5edb7ecc809e2e683134a66b0dcb5ab7d7936c099af4633addf83bc633236b
   languageName: node
   linkType: hard
 
@@ -11757,13 +11536,13 @@ __metadata:
   languageName: node
   linkType: hard
 
-"input-otp@npm:1.2.5":
-  version: 1.2.5
-  resolution: "input-otp@npm:1.2.5"
+"input-otp@npm:1.4.0":
+  version: 1.4.0
+  resolution: "input-otp@npm:1.4.0"
   peerDependencies:
     react: ^16.8 || ^17.0 || ^18.0 || ^19.0
     react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0
-  checksum: 10/3102a27919b401b8b6a117b579b8179bc41103920b903023b05e6fa7c32f7185f44442d1092d0bd48643e678e980d13da2122a2c9d4b3ad7028b9948e2a32536
+  checksum: 10/e727e707389868b65539395afd3f52e16a6d223cc8752e66fe13c6d54d1055d05bebd4317f68aaf97bbe682054ddf6f3e0e28be331b3a728981822064fef3bc1
   languageName: node
   linkType: hard
 
@@ -15532,9 +15311,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"recharts@npm:2.13.1":
-  version: 2.13.1
-  resolution: "recharts@npm:2.13.1"
+"recharts@npm:2.13.3":
+  version: 2.13.3
+  resolution: "recharts@npm:2.13.3"
   dependencies:
     clsx: "npm:^2.0.0"
     eventemitter3: "npm:^4.0.1"
@@ -15547,7 +15326,7 @@ __metadata:
   peerDependencies:
     react: ^16.0.0 || ^17.0.0 || ^18.0.0
     react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0
-  checksum: 10/be4cb77717e99da00c2900985d2f2168e649838fb5a94ac62f1fa2cfc750884fc715d8aad83aed50ad6be77e02058eaba13ed767aafd2eaff9e2abca42489586
+  checksum: 10/0871fbd281c341a45700a7b8d585e5aae6b77d7e8d5fa810ff92c3f0256f905c8d9eaab15be29cd6aa34dde6e899d13a91964a08ea66a643b6884f7374f3060d
   languageName: node
   linkType: hard
 
@@ -15664,9 +15443,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"remix-development-tools@npm:4.7.3":
-  version: 4.7.3
-  resolution: "remix-development-tools@npm:4.7.3"
+"remix-development-tools@npm:4.7.5":
+  version: 4.7.5
+  resolution: "remix-development-tools@npm:4.7.5"
   dependencies:
     "@radix-ui/react-accordion": "npm:^1.1.2"
     "@radix-ui/react-select": "npm:^1.2.2"
@@ -15685,7 +15464,7 @@ __metadata:
     react: ">=17"
     react-dom: ">=17"
     vite: ">=5.0.0"
-  checksum: 10/c99e9b2072891db09b24a83e59a379b27f65edfd94c80c04f0da8594ce7778b4ea5cccb0ad1c13fc033b45e62fca45ef4dad6e45ff312b255a265548c3c3740c
+  checksum: 10/323bf05c4666150a9ea149d209ad2440cd0f21698c021eda0ea1e718afa712dc4ba7242891dff827b7a5cbc5781dcb5c707bac1d17b38c14375c252a8e3e286a
   languageName: node
   linkType: hard
 
@@ -17136,15 +16915,15 @@ __metadata:
   languageName: node
   linkType: hard
 
-"ts-essentials@npm:10.0.2":
-  version: 10.0.2
-  resolution: "ts-essentials@npm:10.0.2"
+"ts-essentials@npm:10.0.3":
+  version: 10.0.3
+  resolution: "ts-essentials@npm:10.0.3"
   peerDependencies:
     typescript: ">=4.5.0"
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 10/f557d940acf8c80c7807530a5a2985e7426387ddda3213bda9990ee072c6360ada52bb0651ee40aa3e6c62d834b57210a61a3043d137f6b617193bb4069d9555
+  checksum: 10/e16911d8bd257d5c46d528a967dd8e8783e8e4c6a529e2afd5bbe0af7de8bd9c15d0808d24620798e64d56917fb484c498ca901075cd4c16a91ac3a75ba6b32e
   languageName: node
   linkType: hard
 


Test patch: