Files
sofa/apps/web/src/components/settings/integrations-section.tsx
T
jake b0172a2b25 feat: refactor platforms to support multiple TMDB provider IDs per platform
- Replace `tmdbProviderId` (single int) with a many-to-many `platformTmdbProviders` join table so one platform entry can map to multiple TMDB provider IDs (e.g. a single "Max" platform covers several regional TMDB IDs)
- Add `isSubscription` flag to platforms to distinguish subscription services from transactional ones, replacing the old `displayOrder` field in API responses
- Add `getPlatformTmdbIds` / `getPlatformTmdbIdMap` helpers in `@sofa/core/platforms` and thread them through discover, explore, and platform list procedures
- Replace `providerId: number` with `platformId: string` (UUID) in discover input schema so the client never needs to resolve TMDB IDs
- Add `scripts/sync-tmdb-providers.ts` script to pull live provider data from TMDB and update `platforms.json`
- Split native title detail availability into separate "Stream" and "Buy or Rent" sections matching the web pattern
- Add two new DB migrations for the join table and platform schema changes
2026-03-24 20:54:34 -04:00

47 lines
1.5 KiB
TypeScript

import { useQuery } from "@tanstack/react-query";
import { useState } from "react";
import { Skeleton } from "@/components/ui/skeleton";
import { orpc } from "@/lib/orpc/client";
import { IntegrationCard, type IntegrationConnection } from "./integration-card";
import { INTEGRATION_CONFIGS } from "./integration-configs";
export function IntegrationsSection() {
const { data, isPending } = useQuery(orpc.integrations.list.queryOptions());
const [localConnections, setLocalConnections] = useState<IntegrationConnection[] | null>(null);
// Use local state if user has modified connections, else use query data
const connections = localConnections ?? data?.integrations ?? [];
function handleSetConnections(
updater: IntegrationConnection[] | ((prev: IntegrationConnection[]) => IntegrationConnection[]),
) {
setLocalConnections((prev) => {
const current = prev ?? data?.integrations ?? [];
return typeof updater === "function" ? updater(current) : updater;
});
}
return isPending ? (
<div className="space-y-2.5">
{INTEGRATION_CONFIGS.map((c) => (
<Skeleton key={c.provider} className="h-20 w-full rounded-xl" />
))}
</div>
) : (
<div className="space-y-2.5">
{INTEGRATION_CONFIGS.map((config) => (
<IntegrationCard
key={config.provider}
config={config}
connection={
connections.find((c: IntegrationConnection) => c.provider === config.provider) ?? null
}
setConnections={handleSetConnections}
/>
))}
</div>
);
}