"use client" import { useMutation, useQueryClient } from "@tanstack/react-query" import { createSupabaseBrowserClient } from "@/lib/supabase/client" import { queryKeys } from "./query-keys" import { notify } from "@/lib/notify" export function useUpdateSubscriptionHiddenFromTimeline() { const supabaseClient = createSupabaseBrowserClient() const queryClient = useQueryClient() return useMutation({ mutationFn: async ({ subscriptionIdentifier, hiddenFromTimeline, }: { subscriptionIdentifier: string hiddenFromTimeline: boolean }) => { const { error } = await supabaseClient .from("subscriptions") .update({ hidden_from_timeline: hiddenFromTimeline }) .eq("id", subscriptionIdentifier) if (error) throw error }, onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: queryKeys.subscriptions.all }) queryClient.invalidateQueries({ queryKey: queryKeys.timeline.all }) notify(variables.hiddenFromTimeline ? "feed hidden from timeline" : "feed visible in timeline") }, onError: (error: Error) => { notify("failed to update visibility: " + error.message) }, }) } export function useUpdateSubscriptionTitle() { const supabaseClient = createSupabaseBrowserClient() const queryClient = useQueryClient() return useMutation({ mutationFn: async ({ subscriptionIdentifier, customTitle, }: { subscriptionIdentifier: string customTitle: string | null }) => { const { error } = await supabaseClient .from("subscriptions") .update({ custom_title: customTitle }) .eq("id", subscriptionIdentifier) if (error) throw error }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.subscriptions.all }) queryClient.invalidateQueries({ queryKey: queryKeys.timeline.all }) notify("title updated") }, onError: (error: Error) => { notify("failed to update title: " + error.message) }, }) } export function useMoveSubscriptionToFolder() { const supabaseClient = createSupabaseBrowserClient() const queryClient = useQueryClient() return useMutation({ mutationFn: async ({ subscriptionIdentifier, folderIdentifier, }: { subscriptionIdentifier: string folderIdentifier: string | null feedTitle?: string sourceFolderName?: string folderName?: string }) => { let query = supabaseClient .from("subscriptions") .select("position") .order("position", { ascending: false }) .limit(1) if (folderIdentifier) { query = query.eq("folder_id", folderIdentifier) } else { query = query.is("folder_id", null) } const { data: maxRow } = await query.maybeSingle() const nextPosition = (maxRow?.position ?? 0) + 1000 const { error } = await supabaseClient .from("subscriptions") .update({ folder_id: folderIdentifier, position: nextPosition }) .eq("id", subscriptionIdentifier) if (error) throw error }, onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: queryKeys.subscriptions.all }) const source = variables.sourceFolderName ?? "no folder" const destination = variables.folderName ?? "no folder" const feedLabel = variables.feedTitle ?? "feed" notify(`moved "${feedLabel}" from ${source} to ${destination}`) }, onError: (error: Error) => { notify("failed to move feed: " + error.message) }, }) } export function useUnsubscribe() { const supabaseClient = createSupabaseBrowserClient() const queryClient = useQueryClient() return useMutation({ mutationFn: async ({ subscriptionIdentifier, }: { subscriptionIdentifier: string feedTitle?: string }) => { const { error } = await supabaseClient .from("subscriptions") .delete() .eq("id", subscriptionIdentifier) if (error) throw error }, onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: queryKeys.subscriptions.all }) queryClient.invalidateQueries({ queryKey: queryKeys.timeline.all }) queryClient.invalidateQueries({ queryKey: queryKeys.userProfile.all }) notify(`unsubscribed from ${variables.feedTitle ?? "feed"}`) }, onError: (error: Error) => { notify("failed to unsubscribe: " + error.message) }, }) } export function useUnsubscribeAll() { const supabaseClient = createSupabaseBrowserClient() const queryClient = useQueryClient() return useMutation({ mutationFn: async () => { const { data: { user }, } = await supabaseClient.auth.getUser() if (!user) throw new Error("not authenticated") const { error } = await supabaseClient .from("subscriptions") .delete() .eq("user_id", user.id) if (error) throw error }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.subscriptions.all }) queryClient.invalidateQueries({ queryKey: queryKeys.timeline.all }) queryClient.invalidateQueries({ queryKey: queryKeys.unreadCounts.all }) queryClient.invalidateQueries({ queryKey: queryKeys.userProfile.all }) notify("all feeds removed") }, onError: (error: Error) => { notify("failed to remove all feeds: " + error.message) }, }) } export function useUpdateFeedUrl() { const supabaseClient = createSupabaseBrowserClient() const queryClient = useQueryClient() return useMutation({ mutationFn: async ({ feedIdentifier, feedUrl, }: { feedIdentifier: string feedUrl: string }) => { const { error } = await supabaseClient.rpc("update_feed_url", { target_feed_id: feedIdentifier, new_url: feedUrl, }) if (error) throw error }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.subscriptions.all }) notify("feed url updated") }, onError: (error: Error) => { notify("failed to update feed url: " + error.message) }, }) } export function useUpdateFeedCredentials() { const supabaseClient = createSupabaseBrowserClient() const queryClient = useQueryClient() return useMutation({ mutationFn: async ({ feedIdentifier, authenticationType, credential, }: { feedIdentifier: string authenticationType: string credential: string }) => { const { error } = await supabaseClient.rpc("update_feed_credentials", { p_feed_id: feedIdentifier, p_auth_type: authenticationType, p_credential: credential, }) if (error) throw error }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.subscriptions.all }) notify("credentials updated") }, onError: (error: Error) => { notify("failed to update credentials: " + error.message) }, }) } export function useAddFeedCredentials() { const supabaseClient = createSupabaseBrowserClient() const queryClient = useQueryClient() return useMutation({ mutationFn: async ({ subscriptionIdentifier, authenticationType, credential, }: { subscriptionIdentifier: string authenticationType: string credential: string }) => { const { error } = await supabaseClient.rpc("add_feed_credentials", { p_subscription_id: subscriptionIdentifier, p_auth_type: authenticationType, p_credential: credential, }) if (error) throw error }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.subscriptions.all }) queryClient.invalidateQueries({ queryKey: queryKeys.timeline.all }) notify("credentials added — feed converted to authenticated") }, onError: (error: Error) => { notify("failed to add credentials: " + error.message) }, }) } export function useRequestFeedRefresh() { const supabaseClient = createSupabaseBrowserClient() return useMutation({ mutationFn: async ({ subscriptionIdentifier, }: { subscriptionIdentifier: string }) => { const { error } = await supabaseClient.rpc("request_feed_refresh", { target_subscription_id: subscriptionIdentifier, }) if (error) throw error }, onSuccess: () => { notify("refresh requested") }, onError: (error: Error) => { notify(error.message.includes("Pro") ? "manual refresh requires a pro subscription" : "failed to request refresh: " + error.message) }, }) }