diff options
| author | Fuwn <[email protected]> | 2026-02-10 00:12:25 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-10 00:12:25 -0800 |
| commit | 32219ec9656e7f46e516c7c41c133133d008e9a4 (patch) | |
| tree | e335fa4b2e32f562b0861cd02a1abe618e8cb6b9 /apps/web/app/reader | |
| parent | fix: P2 security hardening and tier limit parity (diff) | |
| download | asa.news-32219ec9656e7f46e516c7c41c133133d008e9a4.tar.xz asa.news-32219ec9656e7f46e516c7c41c133133d008e9a4.zip | |
fix: reduce lint warnings from 34 to 0
Disable no-img-element (RSS reader needs <img> for arbitrary external
URLs). Remove unused variables/imports and redundant getUser() calls
guarded by middleware. Fix exhaustive-deps by adding stable deps,
wrapping handlers in useCallback, and suppressing intentional omissions.
Fix ref cleanup in use-realtime-entries. Allow triple-slash TS reference
directives in no-comments rule.
Diffstat (limited to 'apps/web/app/reader')
14 files changed, 20 insertions, 34 deletions
diff --git a/apps/web/app/reader/_components/add-feed-dialog.tsx b/apps/web/app/reader/_components/add-feed-dialog.tsx index 4ffbd39..ba02197 100644 --- a/apps/web/app/reader/_components/add-feed-dialog.tsx +++ b/apps/web/app/reader/_components/add-feed-dialog.tsx @@ -1,6 +1,6 @@ "use client" -import { useState, useEffect, useRef } from "react" +import { useState, useEffect, useCallback, useRef } from "react" import { useSubscribeToFeed } from "@/lib/queries/use-subscribe-to-feed" import { useSubscriptions } from "@/lib/queries/use-subscriptions" import { useUserProfile } from "@/lib/queries/use-user-profile" @@ -23,14 +23,14 @@ export function AddFeedDialog() { const supportsAuthenticatedFeeds = userProfile?.tier === "pro" || userProfile?.tier === "developer" - function handleClose() { + const handleClose = useCallback(() => { setFeedUrl("") setCustomTitle("") setSelectedFolderIdentifier(null) setAuthenticationType("none") setFeedCredential("") setOpen(false) - } + }, [setOpen]) async function handleSubmit(event: React.FormEvent) { event.preventDefault() @@ -68,7 +68,7 @@ export function AddFeedDialog() { document.addEventListener("keydown", handleKeyDown, true) return () => document.removeEventListener("keydown", handleKeyDown, true) - }, [isOpen]) + }, [isOpen, handleClose]) useEffect(() => { if (isOpen) { diff --git a/apps/web/app/reader/_components/entry-detail-panel.tsx b/apps/web/app/reader/_components/entry-detail-panel.tsx index 9848d3f..7901100 100644 --- a/apps/web/app/reader/_components/entry-detail-panel.tsx +++ b/apps/web/app/reader/_components/entry-detail-panel.tsx @@ -150,6 +150,7 @@ export function EntryDetailPanel({ }, 1500) return () => clearTimeout(autoReadTimeout) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [entryIdentifier, currentEntry?.isRead]) const contentHtml = diff --git a/apps/web/app/reader/_components/entry-list.tsx b/apps/web/app/reader/_components/entry-list.tsx index 65e35f7..7513d18 100644 --- a/apps/web/app/reader/_components/entry-list.tsx +++ b/apps/web/app/reader/_components/entry-list.tsx @@ -80,6 +80,7 @@ export function EntryList({ const prefetchIdentifiers = useMemo( () => allEntries.map((entry) => entry.entryIdentifier), + // eslint-disable-next-line react-hooks/exhaustive-deps [firstEntryIdentifier, lastEntryIdentifier, allEntries.length] ) usePrefetchEntryDetails(prefetchIdentifiers) @@ -141,6 +142,7 @@ export function EntryList({ if (focusedIndex !== -1) { virtualizer.scrollToIndex(focusedIndex, { align: "auto" }) } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [focusedEntryIdentifier]) if (isLoading) { diff --git a/apps/web/app/reader/_components/mfa-challenge.tsx b/apps/web/app/reader/_components/mfa-challenge.tsx index 347d8b4..b7f86a9 100644 --- a/apps/web/app/reader/_components/mfa-challenge.tsx +++ b/apps/web/app/reader/_components/mfa-challenge.tsx @@ -26,6 +26,7 @@ export function MfaChallenge({ onVerified }: { onVerified: () => void }) { } loadFactor() + // eslint-disable-next-line react-hooks/exhaustive-deps }, []) async function handleVerify(event?: React.FormEvent) { diff --git a/apps/web/app/reader/_components/reader-layout-shell.tsx b/apps/web/app/reader/_components/reader-layout-shell.tsx index 391e6a4..7ec1002 100644 --- a/apps/web/app/reader/_components/reader-layout-shell.tsx +++ b/apps/web/app/reader/_components/reader-layout-shell.tsx @@ -152,7 +152,7 @@ export function ReaderLayoutShell({ maximumItemWidth = Math.max(maximumItemWidth, 192) return `${Math.ceil(maximumItemWidth)}px` - }, [subscriptionsData, customFeedsData, userProfile, displayDensity, showFeedFavicons]) + }, [subscriptionsData, customFeedsData, userProfile, showFeedFavicons]) const sidebarLayout = useDefaultLayout({ id: "asa-sidebar-layout", diff --git a/apps/web/app/reader/_components/reader-shell.tsx b/apps/web/app/reader/_components/reader-shell.tsx index 65a4900..1d50dc2 100644 --- a/apps/web/app/reader/_components/reader-shell.tsx +++ b/apps/web/app/reader/_components/reader-shell.tsx @@ -18,7 +18,6 @@ import { useRealtimeEntries } from "@/lib/hooks/use-realtime-entries" import { useCustomFeeds } from "@/lib/queries/use-custom-feeds" interface ReaderShellProperties { - userEmailAddress: string | null feedFilter: "all" | "saved" folderIdentifier?: string | null feedIdentifier?: string | null @@ -26,7 +25,6 @@ interface ReaderShellProperties { } export function ReaderShell({ - userEmailAddress, feedFilter, folderIdentifier, feedIdentifier, diff --git a/apps/web/app/reader/highlights/_components/highlights-content.tsx b/apps/web/app/reader/highlights/_components/highlights-content.tsx index 4034210..0366935 100644 --- a/apps/web/app/reader/highlights/_components/highlights-content.tsx +++ b/apps/web/app/reader/highlights/_components/highlights-content.tsx @@ -355,10 +355,11 @@ export function HighlightsContent() { useEffect(() => { setSelectedEntryIdentifier(null) setNavigableEntryIdentifiers([]) - }, []) + }, [setSelectedEntryIdentifier, setNavigableEntryIdentifiers]) useEffect(() => { setNavigableEntryIdentifiers(entryIdentifiers) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [entryIdentifiers.length, setNavigableEntryIdentifiers]) if (isLoading) { diff --git a/apps/web/app/reader/page.tsx b/apps/web/app/reader/page.tsx index 4773fd8..068de7d 100644 --- a/apps/web/app/reader/page.tsx +++ b/apps/web/app/reader/page.tsx @@ -1,4 +1,3 @@ -import { createSupabaseServerClient } from "@/lib/supabase/server" import { ReaderShell } from "./_components/reader-shell" export default async function ReaderPage({ @@ -6,16 +5,10 @@ export default async function ReaderPage({ }: { searchParams: Promise<{ folder?: string; feed?: string; custom_feed?: string }> }) { - const supabaseClient = await createSupabaseServerClient() - const { - data: { user }, - } = await supabaseClient.auth.getUser() - const resolvedSearchParams = await searchParams return ( <ReaderShell - userEmailAddress={user?.email ?? null} feedFilter="all" folderIdentifier={resolvedSearchParams.folder} feedIdentifier={resolvedSearchParams.feed} diff --git a/apps/web/app/reader/saved/page.tsx b/apps/web/app/reader/saved/page.tsx index 0ad5ba3..dd362da 100644 --- a/apps/web/app/reader/saved/page.tsx +++ b/apps/web/app/reader/saved/page.tsx @@ -1,15 +1,8 @@ -import { createSupabaseServerClient } from "@/lib/supabase/server" import { ReaderShell } from "../_components/reader-shell" -export default async function SavedPage() { - const supabaseClient = await createSupabaseServerClient() - const { - data: { user }, - } = await supabaseClient.auth.getUser() - +export default function SavedPage() { return ( <ReaderShell - userEmailAddress={user?.email ?? null} feedFilter="saved" /> ) diff --git a/apps/web/app/reader/settings/_components/account-settings.tsx b/apps/web/app/reader/settings/_components/account-settings.tsx index 84b8414..9679e3b 100644 --- a/apps/web/app/reader/settings/_components/account-settings.tsx +++ b/apps/web/app/reader/settings/_components/account-settings.tsx @@ -189,6 +189,7 @@ export function AccountSettings() { useEffect(() => { loadFactors() + // eslint-disable-next-line react-hooks/exhaustive-deps }, []) async function handleBeginEnrollment() { diff --git a/apps/web/app/reader/settings/_components/billing-settings.tsx b/apps/web/app/reader/settings/_components/billing-settings.tsx index 79269fc..1e38684 100644 --- a/apps/web/app/reader/settings/_components/billing-settings.tsx +++ b/apps/web/app/reader/settings/_components/billing-settings.tsx @@ -177,6 +177,7 @@ export function BillingSettings() { url.searchParams.delete("billing") window.history.replaceState({}, "", url.pathname) } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [searchParameters, queryClient]) if (isLoading) { diff --git a/apps/web/app/reader/settings/_components/folders-settings.tsx b/apps/web/app/reader/settings/_components/folders-settings.tsx index 2c3d5f2..3bc0b7b 100644 --- a/apps/web/app/reader/settings/_components/folders-settings.tsx +++ b/apps/web/app/reader/settings/_components/folders-settings.tsx @@ -114,14 +114,7 @@ export function FoldersSettings() { ) } -function FolderRow({ - folderIdentifier, - name, - iconUrl, - feedCount, - onSave, - onDelete, -}: { +function FolderRow(properties: { folderIdentifier: string name: string iconUrl: string | null @@ -129,6 +122,7 @@ function FolderRow({ onSave: (name: string, iconUrl: string | null) => void onDelete: () => void }) { + const { name, iconUrl, feedCount, onSave, onDelete } = properties const [isEditing, setIsEditing] = useState(false) const [editedName, setEditedName] = useState(name) const [editedIconUrl, setEditedIconUrl] = useState(iconUrl ?? "") diff --git a/apps/web/app/reader/settings/_components/import-export-settings.tsx b/apps/web/app/reader/settings/_components/import-export-settings.tsx index 27f8933..f0ba3f3 100644 --- a/apps/web/app/reader/settings/_components/import-export-settings.tsx +++ b/apps/web/app/reader/settings/_components/import-export-settings.tsx @@ -61,7 +61,7 @@ export function ImportExportSettings() { for (const group of parsedGroups) { for (const feed of group.feeds) { try { - await new Promise<void>((resolve, reject) => { + await new Promise<void>((resolve) => { subscribeToFeed.mutate( { feedUrl: feed.url, @@ -72,7 +72,7 @@ export function ImportExportSettings() { importedCount++ resolve() }, - onError: (error) => { + onError: () => { failedCount++ resolve() }, diff --git a/apps/web/app/reader/shares/_components/shares-content.tsx b/apps/web/app/reader/shares/_components/shares-content.tsx index b05d562..db50bc7 100644 --- a/apps/web/app/reader/shares/_components/shares-content.tsx +++ b/apps/web/app/reader/shares/_components/shares-content.tsx @@ -411,12 +411,13 @@ export function SharesContent() { useEffect(() => { setSelectedEntryIdentifier(null) setNavigableEntryIdentifiers([]) - }, []) + }, [setSelectedEntryIdentifier, setNavigableEntryIdentifiers]) useEffect(() => { setNavigableEntryIdentifiers( sharesList.map((share) => share.entryIdentifier) ) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [sharesList.length, setNavigableEntryIdentifiers]) if (isLoading) { |