mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 01:35:39 -04:00
refactor: consolidate watchlist states (#18)
- Rename `watchlist` → `in_watchlist` and `in_progress` → `watching` across the full stack (DB migration, Drizzle schema, core services, API contract, web, native) - Add a new `caught_up` status for TV shows where all aired episodes are watched but the show is still airing - Add `titles.watchAll` procedure and `markAllWatched` action to mark every episode of a TV show as watched in one step; replace the old "Mark as Watching" / "Mark as Completed" context-menu actions with "Mark All Watched" (TV) and "Mark as Watched" (movie) - Extract `display-status.ts` in `@sofa/api` to share status → display label/color logic between web and native - Add `getDisplayStatusesByTitleIds` to `@sofa/core/tracking` and wire it into the dashboard library feed so clients receive resolved display statuses - Show a destructive Alert confirmation before removing a title from the library (native) - Remove "Mark as Completed" from the continue-watching card context menu - Update i18n catalogs for all 6 locales (de, en, es, fr, it, pt)
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
getWatchCount,
|
||||
getWatchHistory,
|
||||
} from "@sofa/core/discovery";
|
||||
import { getDisplayStatusesByTitleIds } from "@sofa/core/tracking";
|
||||
import { tmdbImageUrl } from "@sofa/tmdb/image";
|
||||
|
||||
import { os } from "../context";
|
||||
@@ -48,6 +49,10 @@ export const library = os.dashboard.library.use(authed).handler(({ input, contex
|
||||
totalPages,
|
||||
totalResults,
|
||||
} = getLibraryFeed(context.user.id, input.page, input.limit);
|
||||
|
||||
const titleIds = feed.map((t) => t.titleId);
|
||||
const displayStatuses = getDisplayStatusesByTitleIds(context.user.id, titleIds);
|
||||
|
||||
const items = feed.map((t) => ({
|
||||
id: t.titleId,
|
||||
tmdbId: t.tmdbId,
|
||||
@@ -58,7 +63,7 @@ export const library = os.dashboard.library.use(authed).handler(({ input, contex
|
||||
releaseDate: t.releaseDate ?? null,
|
||||
firstAirDate: t.firstAirDate ?? null,
|
||||
voteAverage: t.voteAverage,
|
||||
userStatus: t.userStatus,
|
||||
userStatus: displayStatuses[t.titleId] ?? null,
|
||||
}));
|
||||
return { items, page, totalPages, totalResults };
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ORPCError } from "@orpc/server";
|
||||
|
||||
import { AppErrorCode } from "@sofa/api/errors";
|
||||
import { ensureBrowseTitlesExist } from "@sofa/core/metadata";
|
||||
import { getEpisodeProgressByTitleIds, getUserStatusesByTitleIds } from "@sofa/core/tracking";
|
||||
import { getEpisodeProgressByTitleIds, getDisplayStatusesByTitleIds } from "@sofa/core/tracking";
|
||||
import { discover as discoverTmdb } from "@sofa/tmdb/client";
|
||||
import { isTmdbConfigured } from "@sofa/tmdb/config";
|
||||
import { tmdbImageUrl } from "@sofa/tmdb/image";
|
||||
@@ -61,7 +61,7 @@ export const discover = os.discover.use(authed).handler(async ({ input, context
|
||||
const [userStatuses, episodeProgress] =
|
||||
titleIds.length > 0
|
||||
? [
|
||||
getUserStatusesByTitleIds(context.user.id, titleIds),
|
||||
getDisplayStatusesByTitleIds(context.user.id, titleIds),
|
||||
getEpisodeProgressByTitleIds(context.user.id, titleIds),
|
||||
]
|
||||
: [{}, {}];
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ORPCError } from "@orpc/server";
|
||||
|
||||
import { AppErrorCode } from "@sofa/api/errors";
|
||||
import { ensureBrowseTitlesExist } from "@sofa/core/metadata";
|
||||
import { getEpisodeProgressByTitleIds, getUserStatusesByTitleIds } from "@sofa/core/tracking";
|
||||
import { getEpisodeProgressByTitleIds, getDisplayStatusesByTitleIds } from "@sofa/core/tracking";
|
||||
import { getGenres, getPopular, getTrending } from "@sofa/tmdb/client";
|
||||
import { isTmdbConfigured } from "@sofa/tmdb/config";
|
||||
import { tmdbImageUrl } from "@sofa/tmdb/image";
|
||||
@@ -90,7 +90,7 @@ export const trending = os.explore.trending.use(authed).handler(async ({ input,
|
||||
const [userStatuses, episodeProgress] =
|
||||
titleIds.length > 0
|
||||
? [
|
||||
getUserStatusesByTitleIds(context.user.id, titleIds),
|
||||
getDisplayStatusesByTitleIds(context.user.id, titleIds),
|
||||
getEpisodeProgressByTitleIds(context.user.id, titleIds),
|
||||
]
|
||||
: [{}, {}];
|
||||
@@ -136,7 +136,7 @@ export const popular = os.explore.popular.use(authed).handler(async ({ input, co
|
||||
const [userStatuses, episodeProgress] =
|
||||
titleIds.length > 0
|
||||
? [
|
||||
getUserStatusesByTitleIds(context.user.id, titleIds),
|
||||
getDisplayStatusesByTitleIds(context.user.id, titleIds),
|
||||
getEpisodeProgressByTitleIds(context.user.id, titleIds),
|
||||
]
|
||||
: [{}, {}];
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ORPCError } from "@orpc/server";
|
||||
|
||||
import { AppErrorCode } from "@sofa/api/errors";
|
||||
import { fetchFullFilmography, getOrFetchPerson } from "@sofa/core/person";
|
||||
import { getUserStatusesByTitleIds } from "@sofa/core/tracking";
|
||||
import { getDisplayStatusesByTitleIds } from "@sofa/core/tracking";
|
||||
|
||||
import { os } from "../context";
|
||||
import { authed } from "../middleware";
|
||||
@@ -20,7 +20,7 @@ export const detail = os.people.detail.use(authed).handler(async ({ input, conte
|
||||
const start = (input.page - 1) * input.limit;
|
||||
const pageCredits = allCredits.slice(start, start + input.limit);
|
||||
|
||||
const userStatuses = getUserStatusesByTitleIds(
|
||||
const userStatuses = getDisplayStatusesByTitleIds(
|
||||
context.user.id,
|
||||
pageCredits.map((c) => c.titleId),
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { AppErrorCode } from "@sofa/api/errors";
|
||||
import { getRecommendationsForTitle } from "@sofa/core/discovery";
|
||||
import { getOrFetchTitle, getOrFetchTitleByTmdbId } from "@sofa/core/metadata";
|
||||
import {
|
||||
getUserStatusesByTitleIds,
|
||||
getDisplayStatusesByTitleIds,
|
||||
getUserTitleInfo,
|
||||
logMovieWatch,
|
||||
markAllEpisodesWatched,
|
||||
@@ -48,14 +48,19 @@ export const watchAll = os.titles.watchAll.use(authed).handler(({ input, context
|
||||
});
|
||||
|
||||
export const userInfo = os.titles.userInfo.use(authed).handler(({ input, context }) => {
|
||||
return getUserTitleInfo(context.user.id, input.id);
|
||||
const info = getUserTitleInfo(context.user.id, input.id);
|
||||
if (!info.status) return { ...info, status: null };
|
||||
|
||||
// Convert stored status to display status
|
||||
const displayStatuses = getDisplayStatusesByTitleIds(context.user.id, [input.id]);
|
||||
return { ...info, status: displayStatuses[input.id] ?? null };
|
||||
});
|
||||
|
||||
export const recommendations = os.titles.recommendations
|
||||
.use(authed)
|
||||
.handler(({ input, context }) => {
|
||||
const recs = getRecommendationsForTitle(input.id);
|
||||
const userStatuses = getUserStatusesByTitleIds(
|
||||
const userStatuses = getDisplayStatusesByTitleIds(
|
||||
context.user.id,
|
||||
recs.map((r) => r.id),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user