fix(tracking): report when a title was already in the library

updateStatus now returns { alreadyAdded }. Native toasts say so instead of
claiming success, and the Explore hero hides Add to Watchlist for library titles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jakeandClaude Opus 5.5 committed 2026-10-05 22:50:04 -04:00
1 parent d6abcbd2bb
commit 8da4cbbe52
19 files changed
+167 -18

No files matched your search

@@ -70,7 +70,9 @@ export default function ExploreScreen() {
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
>
<View className="gap-8">
{heroItem && <HeroBanner item={heroItem} />}
{heroItem && (
<HeroBanner item={{ ...heroItem, userStatus: trendingStatuses[heroItem.id] ?? null }} />
)}
<Animated.View entering={FadeInDown.duration(300).delay(100)}>
<FilterableTitleRow
@@ -21,6 +21,7 @@ export interface HeroBannerItem {
overview?: string | null;
voteAverage?: number | null;
releaseDate?: string | null;
userStatus?: string | null;
}
export function HeroBanner({ item }: { item: HeroBannerItem }) {
@@ -127,13 +128,15 @@ export function HeroBanner({ item }: { item: HeroBannerItem }) {
</Pressable>
</Link.Trigger>
<Link.Preview />
<Link.Menu>
<Link.MenuAction
title={t`Add to Watchlist`}
icon="bookmark"
onPress={() => titleActions.addToWatchlist(item.id, item.title)}
/>
</Link.Menu>
{!item.userStatus && (
<Link.Menu>
<Link.MenuAction
title={t`Add to Watchlist`}
icon="bookmark"
onPress={() => titleActions.addToWatchlist(item.id, item.title)}
/>
</Link.Menu>
)}
</Link>
</Animated.View>
</GestureDetector>
+5 -1
View File
@@ -44,7 +44,11 @@ export function useTitleActions(options?: UseTitleActionsOptions) {
const updateStatus = useMutation(
orpc.tracking.updateStatus.mutationOptions({
onSuccess: (_data, input) => {
onSuccess: (data, input) => {
if (input.status === "watchlist" && data?.alreadyAdded) {
toast.info(t`Already in your library`);
return invalidateTitleQueries();
}
const statusMessages: Record<string, string> = {
watchlist: t`Added to watchlist`,
};
+14 -6
View File
@@ -41,12 +41,20 @@ export function invalidateTitleQueries(): Promise<unknown> {
export const titleActions = {
async addToWatchlist(id: string, titleName?: string) {
try {
await client.tracking.updateStatus({ id, status: "watchlist" });
toast.success(
titleName
? i18n._(msg`Added "${titleName}" to watchlist`)
: i18n._(msg`Added to watchlist`),
);
const result = await client.tracking.updateStatus({ id, status: "watchlist" });
if (result.alreadyAdded) {
toast.info(
titleName
? i18n._(msg`"${titleName}" is already in your library`)
: i18n._(msg`Already in your library`),
);
} else {
toast.success(
titleName
? i18n._(msg`Added "${titleName}" to watchlist`)
: i18n._(msg`Added to watchlist`),
);
}
invalidateTitleQueries();
} catch {
toast.error(i18n._(msg`Failed to add to watchlist`));
+3 -1
View File
@@ -90,7 +90,7 @@ export const updateStatus = os.tracking.updateStatus
.handler(async ({ input, context }) => {
if (input.status === null) {
removeTitleStatus(context.user.id, input.id);
return;
return { alreadyAdded: false };
}
// Auto-import from TMDB if the title is a shell (absorbs quickAdd logic)
@@ -106,6 +106,8 @@ export const updateStatus = os.tracking.updateStatus
log.warn(`Failed to import ${result.type} TMDB ${result.tmdbId}:`, err);
});
}
return { alreadyAdded: result.alreadyAdded };
});
export const rate = os.tracking.rate.use(authed).handler(({ input, context }) => {
+17 -1
View File
@@ -1983,7 +1983,23 @@
},
"responses": {
"200": {
"description": "OK"
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"alreadyAdded": {
"type": "boolean",
"description": "True when the title was already in the library, so nothing changed"
}
},
"required": [
"alreadyAdded"
]
}
}
}
},
"404": {
"description": "404",
+7 -1
View File
@@ -146,7 +146,13 @@ export const contract = {
"Set the user's tracking status for a title. Use null to remove the title from the library entirely.",
})
.input(UpdateStatusInput)
.output(z.void())
.output(
z.object({
alreadyAdded: z
.boolean()
.describe("True when the title was already in the library, so nothing changed"),
}),
)
.errors({
NOT_FOUND: {
message: "Title not found",
+9
View File
@@ -26,6 +26,10 @@ msgstr ""
msgid "...and {remainingErrors} more"
msgstr "...و{remainingErrors} أخرى"
#: apps/native/src/lib/title-actions.ts
msgid "\"{titleName}\" is already in your library"
msgstr ""
#. placeholder {0}: systemHealth.data.imageCache.imageCount
#: apps/native/src/app/(tabs)/(settings)/index.tsx
msgid "{0, plural, one {# image} other {# images}}"
@@ -407,6 +411,11 @@ msgstr "هل لديك حساب بالفعل؟"
msgid "Already have an account? Sign in"
msgstr "هل لديك حساب بالفعل؟ تسجيل الدخول"
#: apps/native/src/hooks/use-title-actions.ts
#: apps/native/src/lib/title-actions.ts
msgid "Already in your library"
msgstr ""
#: apps/web/src/components/titles/title-availability.tsx
msgid "Also available on"
msgstr "متاح أيضاً على"
+9
View File
@@ -26,6 +26,10 @@ msgstr ""
msgid "...and {remainingErrors} more"
msgstr "...und {remainingErrors} weitere"
#: apps/native/src/lib/title-actions.ts
msgid "\"{titleName}\" is already in your library"
msgstr ""
#. placeholder {0}: systemHealth.data.imageCache.imageCount
#: apps/native/src/app/(tabs)/(settings)/index.tsx
msgid "{0, plural, one {# image} other {# images}}"
@@ -407,6 +411,11 @@ msgstr "Bereits ein Konto?"
msgid "Already have an account? Sign in"
msgstr "Bereits ein Konto? Anmelden"
#: apps/native/src/hooks/use-title-actions.ts
#: apps/native/src/lib/title-actions.ts
msgid "Already in your library"
msgstr ""
#: apps/web/src/components/titles/title-availability.tsx
msgid "Also available on"
msgstr "Auch verfügbar auf"
+9
View File
@@ -26,6 +26,10 @@ msgstr ""
msgid "...and {remainingErrors} more"
msgstr "...and {remainingErrors} more"
#: apps/native/src/lib/title-actions.ts
msgid "\"{titleName}\" is already in your library"
msgstr "\"{titleName}\" is already in your library"
#. placeholder {0}: systemHealth.data.imageCache.imageCount
#: apps/native/src/app/(tabs)/(settings)/index.tsx
msgid "{0, plural, one {# image} other {# images}}"
@@ -407,6 +411,11 @@ msgstr ""
msgid "Already have an account? Sign in"
msgstr ""
#: apps/native/src/hooks/use-title-actions.ts
#: apps/native/src/lib/title-actions.ts
msgid "Already in your library"
msgstr "Already in your library"
#: apps/web/src/components/titles/title-availability.tsx
msgid "Also available on"
msgstr "Also available on"
+9
View File
@@ -26,6 +26,10 @@ msgstr ""
msgid "...and {remainingErrors} more"
msgstr "...y {remainingErrors} más"
#: apps/native/src/lib/title-actions.ts
msgid "\"{titleName}\" is already in your library"
msgstr ""
#. placeholder {0}: systemHealth.data.imageCache.imageCount
#: apps/native/src/app/(tabs)/(settings)/index.tsx
msgid "{0, plural, one {# image} other {# images}}"
@@ -407,6 +411,11 @@ msgstr "¿Ya tienes una cuenta?"
msgid "Already have an account? Sign in"
msgstr "¿Ya tienes una cuenta? Inicia sesión"
#: apps/native/src/hooks/use-title-actions.ts
#: apps/native/src/lib/title-actions.ts
msgid "Already in your library"
msgstr ""
#: apps/web/src/components/titles/title-availability.tsx
msgid "Also available on"
msgstr "También disponible en"
+9
View File
@@ -26,6 +26,10 @@ msgstr ""
msgid "...and {remainingErrors} more"
msgstr "...et {remainingErrors} de plus"
#: apps/native/src/lib/title-actions.ts
msgid "\"{titleName}\" is already in your library"
msgstr ""
#. placeholder {0}: systemHealth.data.imageCache.imageCount
#: apps/native/src/app/(tabs)/(settings)/index.tsx
msgid "{0, plural, one {# image} other {# images}}"
@@ -407,6 +411,11 @@ msgstr "Vous avez déjà un compte ?"
msgid "Already have an account? Sign in"
msgstr "Vous avez déjà un compte ? Se connecter"
#: apps/native/src/hooks/use-title-actions.ts
#: apps/native/src/lib/title-actions.ts
msgid "Already in your library"
msgstr ""
#: apps/web/src/components/titles/title-availability.tsx
msgid "Also available on"
msgstr "Aussi disponible sur"
+9
View File
@@ -26,6 +26,10 @@ msgstr ""
msgid "...and {remainingErrors} more"
msgstr "...ועוד {remainingErrors}"
#: apps/native/src/lib/title-actions.ts
msgid "\"{titleName}\" is already in your library"
msgstr ""
#. placeholder {0}: systemHealth.data.imageCache.imageCount
#: apps/native/src/app/(tabs)/(settings)/index.tsx
msgid "{0, plural, one {# image} other {# images}}"
@@ -407,6 +411,11 @@ msgstr "כבר יש לך חשבון?"
msgid "Already have an account? Sign in"
msgstr "כבר יש לך חשבון? התחבר"
#: apps/native/src/hooks/use-title-actions.ts
#: apps/native/src/lib/title-actions.ts
msgid "Already in your library"
msgstr ""
#: apps/web/src/components/titles/title-availability.tsx
msgid "Also available on"
msgstr "זמין גם ב"
+9
View File
@@ -26,6 +26,10 @@ msgstr ""
msgid "...and {remainingErrors} more"
msgstr "...e altri {remainingErrors}"
#: apps/native/src/lib/title-actions.ts
msgid "\"{titleName}\" is already in your library"
msgstr ""
#. placeholder {0}: systemHealth.data.imageCache.imageCount
#: apps/native/src/app/(tabs)/(settings)/index.tsx
msgid "{0, plural, one {# image} other {# images}}"
@@ -407,6 +411,11 @@ msgstr "Hai già un account?"
msgid "Already have an account? Sign in"
msgstr "Hai già un account? Accedi"
#: apps/native/src/hooks/use-title-actions.ts
#: apps/native/src/lib/title-actions.ts
msgid "Already in your library"
msgstr ""
#: apps/web/src/components/titles/title-availability.tsx
msgid "Also available on"
msgstr "Disponibile anche su"
+9
View File
@@ -26,6 +26,10 @@ msgstr ""
msgid "...and {remainingErrors} more"
msgstr "...他{remainingErrors}件"
#: apps/native/src/lib/title-actions.ts
msgid "\"{titleName}\" is already in your library"
msgstr ""
#. placeholder {0}: systemHealth.data.imageCache.imageCount
#: apps/native/src/app/(tabs)/(settings)/index.tsx
msgid "{0, plural, one {# image} other {# images}}"
@@ -407,6 +411,11 @@ msgstr "すでにアカウントをお持ちですか?"
msgid "Already have an account? Sign in"
msgstr "すでにアカウントをお持ちの方はサインイン"
#: apps/native/src/hooks/use-title-actions.ts
#: apps/native/src/lib/title-actions.ts
msgid "Already in your library"
msgstr ""
#: apps/web/src/components/titles/title-availability.tsx
msgid "Also available on"
msgstr "他でも視聴可能"
+9
View File
@@ -26,6 +26,10 @@ msgstr ""
msgid "...and {remainingErrors} more"
msgstr "...그 외 {remainingErrors}개 더"
#: apps/native/src/lib/title-actions.ts
msgid "\"{titleName}\" is already in your library"
msgstr ""
#. placeholder {0}: systemHealth.data.imageCache.imageCount
#: apps/native/src/app/(tabs)/(settings)/index.tsx
msgid "{0, plural, one {# image} other {# images}}"
@@ -407,6 +411,11 @@ msgstr "이미 계정이 있으신가요?"
msgid "Already have an account? Sign in"
msgstr "이미 계정이 있으신가요? 로그인"
#: apps/native/src/hooks/use-title-actions.ts
#: apps/native/src/lib/title-actions.ts
msgid "Already in your library"
msgstr ""
#: apps/web/src/components/titles/title-availability.tsx
msgid "Also available on"
msgstr "다음에서도 이용 가능"
+9
View File
@@ -26,6 +26,10 @@ msgstr ""
msgid "...and {remainingErrors} more"
msgstr "...en {remainingErrors} meer"
#: apps/native/src/lib/title-actions.ts
msgid "\"{titleName}\" is already in your library"
msgstr ""
#. placeholder {0}: systemHealth.data.imageCache.imageCount
#: apps/native/src/app/(tabs)/(settings)/index.tsx
msgid "{0, plural, one {# image} other {# images}}"
@@ -407,6 +411,11 @@ msgstr "Al een account?"
msgid "Already have an account? Sign in"
msgstr "Al een account? Aanmelden"
#: apps/native/src/hooks/use-title-actions.ts
#: apps/native/src/lib/title-actions.ts
msgid "Already in your library"
msgstr ""
#: apps/web/src/components/titles/title-availability.tsx
msgid "Also available on"
msgstr "Ook beschikbaar op"
+9
View File
@@ -26,6 +26,10 @@ msgstr ""
msgid "...and {remainingErrors} more"
msgstr "...e mais {remainingErrors}"
#: apps/native/src/lib/title-actions.ts
msgid "\"{titleName}\" is already in your library"
msgstr ""
#. placeholder {0}: systemHealth.data.imageCache.imageCount
#: apps/native/src/app/(tabs)/(settings)/index.tsx
msgid "{0, plural, one {# image} other {# images}}"
@@ -407,6 +411,11 @@ msgstr "Já tem uma conta?"
msgid "Already have an account? Sign in"
msgstr "Já tem uma conta? Entrar"
#: apps/native/src/hooks/use-title-actions.ts
#: apps/native/src/lib/title-actions.ts
msgid "Already in your library"
msgstr ""
#: apps/web/src/components/titles/title-availability.tsx
msgid "Also available on"
msgstr "Também disponível em"
+9
View File
@@ -26,6 +26,10 @@ msgstr ""
msgid "...and {remainingErrors} more"
msgstr "...及另外 {remainingErrors} 个"
#: apps/native/src/lib/title-actions.ts
msgid "\"{titleName}\" is already in your library"
msgstr ""
#. placeholder {0}: systemHealth.data.imageCache.imageCount
#: apps/native/src/app/(tabs)/(settings)/index.tsx
msgid "{0, plural, one {# image} other {# images}}"
@@ -407,6 +411,11 @@ msgstr "已有账户?"
msgid "Already have an account? Sign in"
msgstr "已有账户?立即登录"
#: apps/native/src/hooks/use-title-actions.ts
#: apps/native/src/lib/title-actions.ts
msgid "Already in your library"
msgstr ""
#: apps/web/src/components/titles/title-availability.tsx
msgid "Also available on"
msgstr "同样在以下平台可用"