aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/app
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2026-02-01 12:29:54 +0000
committerGitHub <noreply@github.com>2026-02-01 12:29:54 +0000
commit65f6e83f11c82b0ec762e11f3392a80e614ee69a (patch)
tree945d8d73122f07fe6a77c2bd3ac9db566939ba3b /apps/web/app
parente516a525bca6f319a2f003e9677624e968b277bf (diff)
downloadkarakeep-65f6e83f11c82b0ec762e11f3392a80e614ee69a.tar.zst
refactor: migrate trpc to the new react query integration mode (#2438)
* refactor: migrate trpc to the new react query integration mode * more fixes * more migrations * upgrade trpc client
Diffstat (limited to 'apps/web/app')
-rw-r--r--apps/web/app/check-email/page.tsx26
-rw-r--r--apps/web/app/reader/[bookmarkId]/page.tsx20
-rw-r--r--apps/web/app/settings/assets/page.tsx20
-rw-r--r--apps/web/app/settings/broken-links/page.tsx16
-rw-r--r--apps/web/app/settings/rules/page.tsx14
-rw-r--r--apps/web/app/settings/stats/page.tsx12
-rw-r--r--apps/web/app/verify-email/page.tsx58
7 files changed, 97 insertions, 69 deletions
diff --git a/apps/web/app/check-email/page.tsx b/apps/web/app/check-email/page.tsx
index 227e116c..9e6a37b8 100644
--- a/apps/web/app/check-email/page.tsx
+++ b/apps/web/app/check-email/page.tsx
@@ -11,26 +11,30 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card";
-import { api } from "@/lib/trpc";
+import { useTRPC } from "@/lib/trpc";
+import { useMutation } from "@tanstack/react-query";
import { Loader2, Mail } from "lucide-react";
export default function CheckEmailPage() {
+ const api = useTRPC();
const searchParams = useSearchParams();
const router = useRouter();
const [message, setMessage] = useState("");
const email = searchParams.get("email");
- const resendEmailMutation = api.users.resendVerificationEmail.useMutation({
- onSuccess: () => {
- setMessage(
- "A new verification email has been sent to your email address.",
- );
- },
- onError: (error) => {
- setMessage(error.message || "Failed to resend verification email.");
- },
- });
+ const resendEmailMutation = useMutation(
+ api.users.resendVerificationEmail.mutationOptions({
+ onSuccess: () => {
+ setMessage(
+ "A new verification email has been sent to your email address.",
+ );
+ },
+ onError: (error) => {
+ setMessage(error.message || "Failed to resend verification email.");
+ },
+ }),
+ );
const handleResendEmail = () => {
if (email) {
diff --git a/apps/web/app/reader/[bookmarkId]/page.tsx b/apps/web/app/reader/[bookmarkId]/page.tsx
index 3eba7c7a..0ba72016 100644
--- a/apps/web/app/reader/[bookmarkId]/page.tsx
+++ b/apps/web/app/reader/[bookmarkId]/page.tsx
@@ -10,22 +10,28 @@ import { FullPageSpinner } from "@/components/ui/full-page-spinner";
import { Separator } from "@/components/ui/separator";
import { useSession } from "@/lib/auth/client";
import { useReaderSettings } from "@/lib/readerSettings";
+import { useQuery } from "@tanstack/react-query";
import { HighlighterIcon as Highlight, Printer, X } from "lucide-react";
-import { api } from "@karakeep/shared-react/trpc";
+import { useTRPC } from "@karakeep/shared-react/trpc";
import { BookmarkTypes } from "@karakeep/shared/types/bookmarks";
import { READER_FONT_FAMILIES } from "@karakeep/shared/types/readers";
import { getBookmarkTitle } from "@karakeep/shared/utils/bookmarkUtils";
export default function ReaderViewPage() {
+ const api = useTRPC();
const params = useParams<{ bookmarkId: string }>();
const bookmarkId = params.bookmarkId;
- const { data: highlights } = api.highlights.getForBookmark.useQuery({
- bookmarkId,
- });
- const { data: bookmark } = api.bookmarks.getBookmark.useQuery({
- bookmarkId,
- });
+ const { data: highlights } = useQuery(
+ api.highlights.getForBookmark.queryOptions({
+ bookmarkId,
+ }),
+ );
+ const { data: bookmark } = useQuery(
+ api.bookmarks.getBookmark.queryOptions({
+ bookmarkId,
+ }),
+ );
const { data: session } = useSession();
const router = useRouter();
diff --git a/apps/web/app/settings/assets/page.tsx b/apps/web/app/settings/assets/page.tsx
index a2d2c9ab..0991816c 100644
--- a/apps/web/app/settings/assets/page.tsx
+++ b/apps/web/app/settings/assets/page.tsx
@@ -16,8 +16,9 @@ import {
} from "@/components/ui/table";
import { ASSET_TYPE_TO_ICON } from "@/lib/attachments";
import { useTranslation } from "@/lib/i18n/client";
-import { api } from "@/lib/trpc";
+import { useTRPC } from "@/lib/trpc";
import { formatBytes } from "@/lib/utils";
+import { useInfiniteQuery } from "@tanstack/react-query";
import { ExternalLink, Trash2 } from "lucide-react";
import { useDetachBookmarkAsset } from "@karakeep/shared-react/hooks/assets";
@@ -28,6 +29,7 @@ import {
} from "@karakeep/trpc/lib/attachments";
export default function AssetsSettingsPage() {
+ const api = useTRPC();
const { t } = useTranslation();
const { mutate: detachAsset, isPending: isDetaching } =
useDetachBookmarkAsset({
@@ -49,13 +51,15 @@ export default function AssetsSettingsPage() {
fetchNextPage,
hasNextPage,
isFetchingNextPage,
- } = api.assets.list.useInfiniteQuery(
- {
- limit: 20,
- },
- {
- getNextPageParam: (lastPage) => lastPage.nextCursor,
- },
+ } = useInfiniteQuery(
+ api.assets.list.infiniteQueryOptions(
+ {
+ limit: 20,
+ },
+ {
+ getNextPageParam: (lastPage) => lastPage.nextCursor,
+ },
+ ),
);
const assets = data?.pages.flatMap((page) => page.assets) ?? [];
diff --git a/apps/web/app/settings/broken-links/page.tsx b/apps/web/app/settings/broken-links/page.tsx
index 139e8f91..4197d62e 100644
--- a/apps/web/app/settings/broken-links/page.tsx
+++ b/apps/web/app/settings/broken-links/page.tsx
@@ -11,6 +11,7 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table";
+import { useQuery, useQueryClient } from "@tanstack/react-query";
import { RefreshCw, Trash2 } from "lucide-react";
import { useTranslation } from "react-i18next";
@@ -18,20 +19,23 @@ import {
useDeleteBookmark,
useRecrawlBookmark,
} from "@karakeep/shared-react/hooks/bookmarks";
-import { api } from "@karakeep/shared-react/trpc";
+import { useTRPC } from "@karakeep/shared-react/trpc";
export default function BrokenLinksPage() {
+ const api = useTRPC();
const { t } = useTranslation();
- const apiUtils = api.useUtils();
- const { data, isPending } = api.bookmarks.getBrokenLinks.useQuery();
+ const queryClient = useQueryClient();
+ const { data, isPending } = useQuery(
+ api.bookmarks.getBrokenLinks.queryOptions(),
+ );
const { mutate: deleteBookmark, isPending: isDeleting } = useDeleteBookmark({
onSuccess: () => {
toast({
description: t("toasts.bookmarks.deleted"),
});
- apiUtils.bookmarks.getBrokenLinks.invalidate();
+ queryClient.invalidateQueries(api.bookmarks.getBrokenLinks.pathFilter());
},
onError: () => {
toast({
@@ -47,7 +51,9 @@ export default function BrokenLinksPage() {
toast({
description: t("toasts.bookmarks.refetch"),
});
- apiUtils.bookmarks.getBrokenLinks.invalidate();
+ queryClient.invalidateQueries(
+ api.bookmarks.getBrokenLinks.pathFilter(),
+ );
},
onError: () => {
toast({
diff --git a/apps/web/app/settings/rules/page.tsx b/apps/web/app/settings/rules/page.tsx
index 17f5b388..6d0b6522 100644
--- a/apps/web/app/settings/rules/page.tsx
+++ b/apps/web/app/settings/rules/page.tsx
@@ -6,21 +6,25 @@ import RuleList from "@/components/dashboard/rules/RuleEngineRuleList";
import { Button } from "@/components/ui/button";
import { FullPageSpinner } from "@/components/ui/full-page-spinner";
import { useTranslation } from "@/lib/i18n/client";
-import { api } from "@/lib/trpc";
+import { useTRPC } from "@/lib/trpc";
+import { useQuery } from "@tanstack/react-query";
import { PlusCircle } from "lucide-react";
import { RuleEngineRule } from "@karakeep/shared/types/rules";
export default function RulesSettingsPage() {
+ const api = useTRPC();
const { t } = useTranslation();
const [editingRule, setEditingRule] = useState<
(Omit<RuleEngineRule, "id"> & { id: string | null }) | null
>(null);
- const { data: rules, isLoading } = api.rules.list.useQuery(undefined, {
- refetchOnWindowFocus: true,
- refetchOnMount: true,
- });
+ const { data: rules, isLoading } = useQuery(
+ api.rules.list.queryOptions(undefined, {
+ refetchOnWindowFocus: true,
+ refetchOnMount: true,
+ }),
+ );
const handleCreateRule = () => {
const newRule = {
diff --git a/apps/web/app/settings/stats/page.tsx b/apps/web/app/settings/stats/page.tsx
index 28c017f5..06076376 100644
--- a/apps/web/app/settings/stats/page.tsx
+++ b/apps/web/app/settings/stats/page.tsx
@@ -6,7 +6,8 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Progress } from "@/components/ui/progress";
import { Skeleton } from "@/components/ui/skeleton";
import { useTranslation } from "@/lib/i18n/client";
-import { api } from "@/lib/trpc";
+import { useTRPC } from "@/lib/trpc";
+import { useQuery } from "@tanstack/react-query";
import {
Archive,
BarChart3,
@@ -159,9 +160,10 @@ function StatCard({
}
export default function StatsPage() {
+ const api = useTRPC();
const { t } = useTranslation();
- const { data: stats, isLoading } = api.users.stats.useQuery();
- const { data: userSettings } = api.users.settings.useQuery();
+ const { data: stats, isLoading } = useQuery(api.users.stats.queryOptions());
+ const { data: userSettings } = useQuery(api.users.settings.queryOptions());
const maxHourlyActivity = useMemo(() => {
if (!stats) return 0;
@@ -237,7 +239,6 @@ export default function StatsPage() {
</p>
</div>
</div>
-
{/* Overview Stats */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<StatCard
@@ -289,7 +290,6 @@ export default function StatsPage() {
description={t("settings.stats.overview.bookmarks_added")}
/>
</div>
-
<div className="grid gap-6 md:grid-cols-2">
{/* Bookmark Types */}
<Card>
@@ -532,7 +532,6 @@ export default function StatsPage() {
</CardContent>
</Card>
</div>
-
{/* Activity Patterns */}
<div className="grid gap-6 md:grid-cols-2">
{/* Hourly Activity */}
@@ -583,7 +582,6 @@ export default function StatsPage() {
</CardContent>
</Card>
</div>
-
{/* Asset Storage */}
{stats.assetsByType.length > 0 && (
<Card>
diff --git a/apps/web/app/verify-email/page.tsx b/apps/web/app/verify-email/page.tsx
index da9b8b6b..7da96761 100644
--- a/apps/web/app/verify-email/page.tsx
+++ b/apps/web/app/verify-email/page.tsx
@@ -11,10 +11,12 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card";
-import { api } from "@/lib/trpc";
+import { useTRPC } from "@/lib/trpc";
+import { useMutation } from "@tanstack/react-query";
import { CheckCircle, Loader2, XCircle } from "lucide-react";
export default function VerifyEmailPage() {
+ const api = useTRPC();
const searchParams = useSearchParams();
const router = useRouter();
const [status, setStatus] = useState<"loading" | "success" | "error">(
@@ -25,32 +27,36 @@ export default function VerifyEmailPage() {
const token = searchParams.get("token");
const email = searchParams.get("email");
- const verifyEmailMutation = api.users.verifyEmail.useMutation({
- onSuccess: () => {
- setStatus("success");
- setMessage(
- "Your email has been successfully verified! You can now sign in.",
- );
- },
- onError: (error) => {
- setStatus("error");
- setMessage(
- error.message ||
- "Failed to verify email. The link may be invalid or expired.",
- );
- },
- });
+ const verifyEmailMutation = useMutation(
+ api.users.verifyEmail.mutationOptions({
+ onSuccess: () => {
+ setStatus("success");
+ setMessage(
+ "Your email has been successfully verified! You can now sign in.",
+ );
+ },
+ onError: (error) => {
+ setStatus("error");
+ setMessage(
+ error.message ||
+ "Failed to verify email. The link may be invalid or expired.",
+ );
+ },
+ }),
+ );
- const resendEmailMutation = api.users.resendVerificationEmail.useMutation({
- onSuccess: () => {
- setMessage(
- "A new verification email has been sent to your email address.",
- );
- },
- onError: (error) => {
- setMessage(error.message || "Failed to resend verification email.");
- },
- });
+ const resendEmailMutation = useMutation(
+ api.users.resendVerificationEmail.mutationOptions({
+ onSuccess: () => {
+ setMessage(
+ "A new verification email has been sent to your email address.",
+ );
+ },
+ onError: (error) => {
+ setMessage(error.message || "Failed to resend verification email.");
+ },
+ }),
+ );
useEffect(() => {
if (token && email) {