mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-07-14 18:15:56 -04:00
* feat: reorganize API around operation domains
Restructure the oRPC contract from 14 resource-oriented routers to 8
domain-oriented routers for a cleaner public API surface.
- Consolidate 7 watch procedures into unified tracking.watch/unwatch
with scope + ids input (movie, episode, season, series)
- Split dashboard across tracking (stats, history), library
(continueWatching, upcoming), and discover (recommendations)
- Merge explore + search + discover into single discover router
- Absorb integrations into account.integrations
- Merge system.authConfig into system.publicInfo
- Collapse 6 admin setting endpoints into admin.settings.get/update
- Deduplicate platforms.list + explore.watchProviders into
discover.platforms
- Add symmetric unwatchMovie/unwatchSeries core functions
- Rename titles.detail→get, titles.recommendations→similar,
people.detail→get
BREAKING CHANGE: All client API paths have changed. REST paths now
mirror router structure.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address review feedback on API reorganization
- Fix updateRating invalidation in native app — was only invalidating
title queries, now calls invalidateTitleQueries() to also refresh
tracking.userInfo (drives the rating UI)
- Make unwatchMovie status revert consistent with unwatchSeries — revert
any non-watchlist status, not just "completed"
- Add sync invariant comment on handleWatch/handleUnwatch loops
- Remove unused queryClient import in native use-title-actions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: updateStatus NOT_FOUND error + rate() invalidation in native
- updateStatus now throws NOT_FOUND when quickAddTitle returns null
(title doesn't exist), instead of silently succeeding
- Add NOT_FOUND error to updateStatus contract definition
- Fix rate() in native title-actions.ts to call invalidateTitleQueries()
instead of only invalidating orpc.titles.key() — mirrors the fix
already applied to the hook-based path in d2ddc0f
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: expand mobile app docs and add Play Store badge
- Add the Google Play badge to the README alongside the App Store badge
- Expand the mobile app docs with the Android/Play Store release details
- Refresh docs site dependencies and related package versions for the updated docs stack
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
53 lines
2.1 KiB
TypeScript
53 lines
2.1 KiB
TypeScript
import { Trans, useLingui } from "@lingui/react/macro";
|
|
import { IconRefresh, IconWebhook } from "@tabler/icons-react-native";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { Pressable, View } from "react-native";
|
|
|
|
import { IntegrationCard } from "@/components/settings/integration-card";
|
|
import { getIntegrationConfigs } from "@/components/settings/integration-configs";
|
|
import { ScaledIcon } from "@/components/ui/scaled-icon";
|
|
import { SectionHeader } from "@/components/ui/section-header";
|
|
import { Spinner } from "@/components/ui/spinner";
|
|
import { Text } from "@/components/ui/text";
|
|
import { orpc } from "@/lib/orpc";
|
|
|
|
export function IntegrationsSection() {
|
|
const { t, i18n } = useLingui();
|
|
const configs = getIntegrationConfigs(i18n);
|
|
const integrations = useQuery(orpc.account.integrations.list.queryOptions());
|
|
|
|
return (
|
|
<View className="mb-6">
|
|
<SectionHeader title={t`Integrations`} icon={IconWebhook} />
|
|
|
|
{integrations.isPending ? (
|
|
<View className="items-center py-4">
|
|
<Spinner colorClassName="accent-primary" />
|
|
</View>
|
|
) : integrations.isError ? (
|
|
<View className="items-center gap-2 py-4">
|
|
<Text className="text-muted-foreground text-sm">
|
|
<Trans>Could not load integrations</Trans>
|
|
</Text>
|
|
<Pressable
|
|
onPress={() => integrations.refetch()}
|
|
className="bg-secondary flex-row items-center gap-1.5 rounded-lg px-3 py-1.5"
|
|
style={{ borderCurve: "continuous" }}
|
|
>
|
|
<ScaledIcon icon={IconRefresh} size={14} className="accent-primary" />
|
|
<Text className="text-primary font-sans text-sm font-medium">
|
|
<Trans>Retry</Trans>
|
|
</Text>
|
|
</Pressable>
|
|
</View>
|
|
) : (
|
|
configs.map((config) => {
|
|
const connection =
|
|
integrations.data?.integrations?.find((i) => i.provider === config.provider) ?? null;
|
|
return <IntegrationCard key={config.provider} config={config} connection={connection} />;
|
|
})
|
|
)}
|
|
</View>
|
|
);
|
|
}
|