Files
streamyfin/components/medialists/MediaListSection.tsx
Fredrik Burmester f7da29b9c9
Some checks failed
🕒 Handle Stale Issues / 🗑️ Cleanup Stale Issues (push) Has been cancelled
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (actions) (push) Has been cancelled
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (javascript-typescript) (push) Has been cancelled
🔒 Lockfile Consistency Check / 🔍 Check bun.lock and package.json consistency (push) Has been cancelled
🏗️ Build Apps / 🤖 Build Android APK (Phone) (push) Has been cancelled
🏗️ Build Apps / 🤖 Build Android APK (TV) (push) Has been cancelled
🏗️ Build Apps / 🍎 Build iOS IPA (Phone) (push) Has been cancelled
🏷️🔀Merge Conflict Labeler / 🏷️ Labeling Merge Conflicts (push) Has been cancelled
🚦 Security & Quality Gate / 📝 Validate PR Title (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Vulnerable Dependencies (push) Has been cancelled
🚦 Security & Quality Gate / 🚑 Expo Doctor Check (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (check) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (format) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (lint) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (typecheck) (push) Has been cancelled
fix: better api calls
2025-11-12 21:30:20 +01:00

99 lines
2.6 KiB
TypeScript

import type {
BaseItemDto,
BaseItemDtoQueryResult,
} from "@jellyfin/sdk/lib/generated-client/models";
import { getItemsApi } from "@jellyfin/sdk/lib/utils/api";
import {
type QueryFunction,
type QueryKey,
useQuery,
} from "@tanstack/react-query";
import { useAtom } from "jotai";
import { useCallback } from "react";
import { View, type ViewProps } from "react-native";
import { useInView } from "@/hooks/useInView";
import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
import { InfiniteHorizontalScroll } from "../common/InfiniteHorizontalScroll";
import { Text } from "../common/Text";
import { TouchableItemRouter } from "../common/TouchableItemRouter";
import { ItemCardText } from "../ItemCardText";
import MoviePoster from "../posters/MoviePoster";
interface Props extends ViewProps {
queryKey: QueryKey;
queryFn: QueryFunction<BaseItemDto>;
scrollY?: number; // For lazy loading
enableLazyLoading?: boolean; // Enable/disable lazy loading
}
export const MediaListSection: React.FC<Props> = ({
queryFn,
queryKey,
scrollY = 0,
enableLazyLoading = false,
...props
}) => {
const [api] = useAtom(apiAtom);
const [user] = useAtom(userAtom);
const { ref, isInView, onLayout } = useInView(scrollY, {
enabled: enableLazyLoading,
});
const { data: collection } = useQuery({
queryKey,
queryFn,
staleTime: 60 * 1000, // 1 minute
enabled: enableLazyLoading ? isInView : true,
});
const fetchItems = useCallback(
async ({
pageParam,
}: {
pageParam: number;
}): Promise<BaseItemDtoQueryResult | null> => {
if (!api || !user?.Id || !collection) return null;
const response = await getItemsApi(api).getItems({
userId: user.Id,
parentId: collection.Id,
startIndex: pageParam,
limit: 8,
});
return response.data;
},
[api, user?.Id, collection?.Id],
);
if (!collection) return null;
return (
<View ref={ref} onLayout={onLayout} {...props}>
<Text className='px-4 text-lg font-bold mb-2 text-neutral-100'>
{collection.Name}
</Text>
<InfiniteHorizontalScroll
height={247}
renderItem={(item, index) => (
<TouchableItemRouter
key={index}
item={item}
className={`flex flex-col
${"w-28"}
`}
>
<View>
<MoviePoster item={item} />
<ItemCardText item={item} />
</View>
</TouchableItemRouter>
)}
queryFn={fetchItems}
queryKey={["media-list", collection.Id!]}
/>
</View>
);
};