"use client" import { useState } from "react" import { useCustomFeeds } from "@/lib/queries/use-custom-feeds" import { useCreateCustomFeed, useUpdateCustomFeed, useDeleteCustomFeed, } from "@/lib/queries/use-custom-feed-mutations" import { useSubscriptions } from "@/lib/queries/use-subscriptions" import { useUserProfile } from "@/lib/queries/use-user-profile" import { TIER_LIMITS } from "@asa-news/shared" export function CustomFeedsSettings() { const { data: customFeeds, isLoading } = useCustomFeeds() const { data: subscriptionsData } = useSubscriptions() const { data: userProfile } = useUserProfile() const createCustomFeed = useCreateCustomFeed() const [newName, setNewName] = useState("") const [newKeywords, setNewKeywords] = useState("") const [newMatchMode, setNewMatchMode] = useState<"and" | "or">("or") const [newSourceFolderId, setNewSourceFolderId] = useState("") const folders = subscriptionsData?.folders ?? [] const tier = userProfile?.tier ?? "free" const maximumCustomFeeds = TIER_LIMITS[tier].maximumCustomFeeds function handleCreate(event: React.FormEvent) { event.preventDefault() const trimmedName = newName.trim() const trimmedKeywords = newKeywords.trim() if (!trimmedName || !trimmedKeywords) return createCustomFeed.mutate({ name: trimmedName, query: trimmedKeywords, matchMode: newMatchMode, sourceFolderIdentifier: newSourceFolderId || null, }) setNewName("") setNewKeywords("") setNewMatchMode("or") setNewSourceFolderId("") } if (isLoading) { return

loading custom feeds ...

} const feedsList = customFeeds ?? [] return (

{feedsList.length} / {maximumCustomFeeds} custom feeds used

setNewName(event.target.value)} placeholder="feed name" className="w-full border border-border bg-background-primary px-3 py-2 text-text-primary outline-none placeholder:text-text-dim focus:border-text-dim" /> setNewKeywords(event.target.value)} placeholder="keywords (space-separated)" className="w-full border border-border bg-background-primary px-3 py-2 text-text-primary outline-none placeholder:text-text-dim focus:border-text-dim" />
{feedsList.length === 0 ? (

no custom feeds yet

) : ( feedsList.map((customFeed) => ( )) )}
) } function CustomFeedRow({ customFeed, folders, }: { customFeed: { identifier: string name: string query: string matchMode: "and" | "or" sourceFolderIdentifier: string | null iconUrl: string | null } folders: { folderIdentifier: string; name: string }[] }) { const updateCustomFeed = useUpdateCustomFeed() const deleteCustomFeed = useDeleteCustomFeed() const [isEditing, setIsEditing] = useState(false) const [editedName, setEditedName] = useState(customFeed.name) const [editedKeywords, setEditedKeywords] = useState(customFeed.query) const [editedMatchMode, setEditedMatchMode] = useState(customFeed.matchMode) const [editedSourceFolderId, setEditedSourceFolderId] = useState( customFeed.sourceFolderIdentifier ?? "" ) const [editedIconUrl, setEditedIconUrl] = useState( customFeed.iconUrl ?? "" ) const [showDeleteConfirm, setShowDeleteConfirm] = useState(false) function handleSave() { const trimmedName = editedName.trim() const trimmedKeywords = editedKeywords.trim() if (!trimmedName || !trimmedKeywords) return updateCustomFeed.mutate({ customFeedIdentifier: customFeed.identifier, name: trimmedName, query: trimmedKeywords, matchMode: editedMatchMode, sourceFolderIdentifier: editedSourceFolderId || null, iconUrl: editedIconUrl.trim() || null, }) setIsEditing(false) } const sourceFolderName = customFeed.sourceFolderIdentifier ? folders.find( (folder) => folder.folderIdentifier === customFeed.sourceFolderIdentifier )?.name ?? "unknown folder" : "all feeds" return (
{isEditing ? (
setEditedName(event.target.value)} className="w-full border border-border bg-background-primary px-2 py-1 text-text-primary outline-none focus:border-text-dim" autoFocus /> setEditedKeywords(event.target.value)} className="w-full border border-border bg-background-primary px-2 py-1 text-text-primary outline-none focus:border-text-dim" />
setEditedIconUrl(event.target.value)} placeholder="icon url (optional)" className="w-full border border-border bg-background-primary px-2 py-1 text-text-primary outline-none placeholder:text-text-dim focus:border-text-dim" />
) : (
{customFeed.name}
{showDeleteConfirm ? (
) : ( )}

keywords: {customFeed.query} ({customFeed.matchMode === "and" ? "all" : "any"})

source: {sourceFolderName}

)}
) }