A personal media tracker built on the AT Protocol opnshelf.xyz
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: fix tsc & agents.md

+54 -26
+3 -3
README.md
··· 223 223 224 224 ```bash 225 225 # Web 226 - cd apps/web && pnpm check && npx tsc --noEmit 226 + cd apps/web && pnpm check && pnpm tsc --noEmit 227 227 228 228 # Backend 229 - cd backend && pnpm lint 229 + cd backend && pnpm check && pnpm tsc --noEmit 230 230 231 231 # Mobile 232 - cd apps/mobile && pnpm typecheck 232 + cd apps/mobile && pnpm check && pnpm tsc --noEmit 233 233 ``` 234 234 235 235 ## License
+1 -2
apps/mobile/components/ui/Input.tsx
··· 53 53 <Search size={20} color={colors.onSurfaceVariant} /> 54 54 </View> 55 55 <TextInput 56 - style={inputTextStyle} 56 + style={[inputTextStyle, { color: colors.onSurface }]} 57 57 value={value} 58 58 placeholderTextColor={colors.onSurfaceVariant} 59 - color={colors.onSurface} 60 59 {...props} 61 60 /> 62 61 {hasValue && onClear && (
+23 -16
apps/web/src/components/DatePickerModal.tsx
··· 63 63 } 64 64 }, [open]); 65 65 66 + const isMovieMode = target.mode === undefined || target.mode === "movie"; 67 + const isEpisodeMode = target.mode === "episode"; 68 + const isSeasonMode = target.mode === "season"; 69 + const isShowMode = target.mode === "show"; 70 + 66 71 const markMutation = useMutation({ 67 - mutationKey: ["movies", target.movieId, "markWatched"], 72 + mutationKey: ["movies", isMovieMode ? target.movieId : "", "markWatched"], 68 73 ...moviesControllerMarkWatchedMutation(), 69 74 onSuccess: () => { 70 - if (target.mode === "episode") { 75 + if (isEpisodeMode) { 71 76 return; 72 77 } 73 78 queryClient.invalidateQueries({ ··· 75 80 path: { userDid: userDid || "" }, 76 81 }), 77 82 }); 78 - queryClient.invalidateQueries({ 79 - queryKey: ["watchHistory", userDid, target.movieId], 80 - }); 83 + if (isMovieMode) { 84 + queryClient.invalidateQueries({ 85 + queryKey: ["watchHistory", userDid, target.movieId], 86 + }); 87 + } 81 88 toast.success("Added to your shelf"); 82 89 onClose(); 83 90 }, ··· 88 95 const markEpisodeMutation = useMutation({ 89 96 mutationKey: [ 90 97 "shows", 91 - target.showId, 98 + isEpisodeMode ? target.showId : "", 92 99 "episodes", 93 - target.episodeNumber, 100 + isEpisodeMode ? target.episodeNumber : "", 94 101 "markWatched", 95 102 ], 96 103 ...showsControllerMarkWatchedMutation(), 97 104 onSuccess: () => { 98 - if (target.mode === "episode") { 105 + if (isEpisodeMode) { 99 106 queryClient.invalidateQueries({ 100 107 queryKey: showsControllerGetUserShowsQueryKey({ 101 108 path: { userDid: userDid || "" }, ··· 117 124 const markSeasonMutation = useMutation({ 118 125 mutationKey: [ 119 126 "shows", 120 - target.showId, 127 + isSeasonMode ? target.showId : "", 121 128 "seasons", 122 - target.seasonNumber, 129 + isSeasonMode ? target.seasonNumber : "", 123 130 "markSeasonWatched", 124 131 ], 125 132 ...showsControllerMarkSeasonWatchedMutation(), 126 133 onSuccess: () => { 127 - if (target.mode === "season") { 134 + if (isSeasonMode) { 128 135 queryClient.invalidateQueries({ 129 136 queryKey: showsControllerGetUserShowsQueryKey({ 130 137 path: { userDid: userDid || "" }, ··· 144 151 }, 145 152 }); 146 153 const markShowMutation = useMutation({ 147 - mutationKey: ["shows", target.showId, "markShowWatched"], 154 + mutationKey: ["shows", isShowMode ? target.showId : "", "markShowWatched"], 148 155 ...showsControllerMarkShowWatchedMutation(), 149 156 onSuccess: () => { 150 - if (target.mode === "show") { 157 + if (isShowMode) { 151 158 queryClient.invalidateQueries({ 152 159 queryKey: showsControllerGetUserShowsQueryKey({ 153 160 path: { userDid: userDid || "" }, ··· 183 190 return; 184 191 } 185 192 186 - if (target.mode === "episode") { 193 + if (isEpisodeMode) { 187 194 markEpisodeMutation.mutate({ 188 195 body: { 189 196 showId: target.showId, ··· 195 202 return; 196 203 } 197 204 198 - if (target.mode === "season") { 205 + if (isSeasonMode) { 199 206 markSeasonMutation.mutate({ 200 207 body: { 201 208 showId: target.showId, ··· 206 213 return; 207 214 } 208 215 209 - if (target.mode === "show") { 216 + if (isShowMode) { 210 217 markShowMutation.mutate({ 211 218 body: { 212 219 showId: target.showId,
+15 -3
apps/web/src/components/ShowGrid.tsx
··· 1 - import type { TmdbShowResultDto } from "@opnshelf/api"; 1 + import type { TmdbShowResultDto, UserDto } from "@opnshelf/api"; 2 2 import { cn } from "@/lib/utils"; 3 3 import { ShowCard } from "./ShowCard"; 4 4 5 5 interface ShowGridProps { 6 6 shows: TmdbShowResultDto[]; 7 + user: UserDto | null | undefined; 8 + watchedShowIds: Set<string>; 7 9 gridClassName?: string; 8 10 } 9 11 10 - export function ShowGrid({ shows, gridClassName }: ShowGridProps) { 12 + export function ShowGrid({ 13 + shows, 14 + user, 15 + watchedShowIds, 16 + gridClassName, 17 + }: ShowGridProps) { 11 18 return ( 12 19 <div 13 20 className={cn( ··· 16 23 )} 17 24 > 18 25 {shows.map((show) => ( 19 - <ShowCard key={show.id} show={show} /> 26 + <ShowCard 27 + key={show.id} 28 + show={show} 29 + user={user} 30 + isWatched={watchedShowIds.has(show.id.toString())} 31 + /> 20 32 ))} 21 33 </div> 22 34 );
-1
apps/web/src/routes/search.tsx
··· 97 97 }, [query, searchQuery, type, navigate]); 98 98 99 99 const hasQuery = searchQuery.length > 0; 100 - const _isAll = type === "all"; 101 100 const isMovies = type === "movies"; 102 101 const isShows = type === "shows"; 103 102
+12
backend/src/movies/movies.service.spec.ts
··· 261 261 backdrop_path: "/backdrop.jpg", 262 262 release_date: "2024-06-15", 263 263 overview: "A great test movie", 264 + popularity: 100.5, 265 + vote_average: 8.5, 266 + vote_count: 1500, 264 267 }; 265 268 const mockUpsertedMovie = { 266 269 movieId: "123", ··· 317 320 backdrop_path: undefined, 318 321 release_date: undefined, 319 322 overview: "No release date", 323 + popularity: 50.0, 324 + vote_average: 7.0, 325 + vote_count: 100, 320 326 }; 321 327 mockColorExtractionService.extractColorsFromPoster.mockResolvedValue( 322 328 null, ··· 357 363 backdrop_path: undefined, 358 364 release_date: "", 359 365 overview: undefined, 366 + popularity: 25.0, 367 + vote_average: 6.5, 368 + vote_count: 50, 360 369 }; 361 370 mockColorExtractionService.extractColorsFromPoster.mockResolvedValue( 362 371 null, ··· 389 398 backdrop_path: undefined, 390 399 release_date: "2025-01-01", 391 400 overview: "Refresh colors", 401 + popularity: 75.0, 402 + vote_average: 7.8, 403 + vote_count: 500, 392 404 }; 393 405 const mockColors = { 394 406 primary: "#60a5fa",
-1
backend/src/search/search.service.ts
··· 3 3 import { ShowsService } from "../shows/shows.service"; 4 4 import { 5 5 type DiscoverQueryDto, 6 - type MediaType, 7 6 type UnifiedDiscoverResponseDto, 8 7 type UnifiedSearchResponseDto, 9 8 type UnifiedSearchResultDto,