Removes Tanstack Query

This commit is contained in:
2025-07-15 10:53:28 -07:00
parent 8f96062058
commit 762306023b
8 changed files with 85 additions and 249 deletions

View File

@@ -1,5 +1,4 @@
import { createContext, useContext, useCallback } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { createContext, useContext, useCallback, useState } from "react";
import type { ReactNode } from "react";
import { pb } from "@/lib/pocketbase";
import type { AuthRecord } from "pocketbase";
@@ -26,91 +25,47 @@ export interface AuthContextValue {
const AuthContext = createContext<AuthContextValue | undefined>(undefined);
/**
* Fetches the currently authenticated user from PocketBase.
*/
async function fetchUser(): Promise<AuthRecord | null> {
if (pb.authStore.isValid) {
return pb.authStore.record;
}
return null;
}
/**
* Provider for authentication context, using TanStack Query for state management.
* Provider for authentication context.
*/
export function AuthProvider({ children }: { children: ReactNode }) {
const queryClient = useQueryClient();
const { data: user, isLoading } = useQuery({
queryKey: ["auth", "user"],
queryFn: fetchUser,
});
const [isLoading, setIsLoading] = useState(false);
const [user, setUser] = useState<AuthRecord | null>(pb.authStore.record);
const navigate = useNavigate();
const loginMutation = useMutation({
mutationFn: async ({
email,
password,
}: {
email: string;
password: string;
}) => {
await pb.collection("users").authWithPassword(email, password);
return fetchUser();
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["auth", "user"] });
},
});
function updateUser() {
if (pb.authStore.isValid) {
setUser(pb.authStore.record);
}
setIsLoading(false);
}
const signupMutation = useMutation({
mutationFn: async ({
email,
password,
passwordConfirm,
}: {
email: string;
password: string;
passwordConfirm: string;
}) => {
await pb.collection("users").create({ email, password, passwordConfirm });
await pb.collection("users").authWithPassword(email, password);
return fetchUser();
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["auth", "user"] });
},
});
const logoutMutation = useMutation({
mutationFn: async () => {
pb.authStore.clear();
return null;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["auth", "user"] });
},
});
const login = useCallback(
async (email: string, password: string) => {
await loginMutation.mutateAsync({ email, password });
navigate({ to: "/campaigns" });
},
[loginMutation],
);
const login = useCallback(async (email: string, password: string) => {
console.log("login");
setIsLoading(true);
await pb.collection("users").authWithPassword(email, password);
updateUser();
navigate({ to: "/campaigns" });
}, []);
const signup = useCallback(
async (email: string, password: string, passwordConfirm: string) => {
await signupMutation.mutateAsync({ email, password, passwordConfirm });
console.log("signup");
setIsLoading(true);
await pb.collection("users").create({ email, password, passwordConfirm });
await pb.collection("users").authWithPassword(email, password);
updateUser();
navigate({ to: "/campaigns" });
},
[signupMutation],
[],
);
const logout = useCallback(async () => {
await logoutMutation.mutateAsync();
console.log("logout");
pb.authStore.clear();
setUser(null);
navigate({ to: "/" });
}, [logoutMutation]);
}, []);
return (
<AuthContext.Provider

View File

@@ -1,7 +1,6 @@
import { StrictMode } from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider, createRouter } from "@tanstack/react-router";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
// Import the generated route tree
import { routeTree } from "./routeTree.gen";
@@ -9,16 +8,13 @@ import { routeTree } from "./routeTree.gen";
import "./styles.css";
import reportWebVitals from "./reportWebVitals.ts";
const queryClient = new QueryClient();
// Create a new router instance
const router = createRouter({
routeTree,
context: { queryClient },
defaultPreload: "intent",
scrollRestoration: true,
defaultStructuralSharing: true,
defaultPreloadStaleTime: 0,
defaultPendingMinMs: 0,
});
// Register the router instance for type safety
@@ -34,9 +30,7 @@ if (rootElement && !rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement);
root.render(
<StrictMode>
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
</QueryClientProvider>
<RouterProvider router={router} />
</StrictMode>,
);
}

View File

@@ -1,6 +1,5 @@
import { AuthProvider } from "@/context/auth/AuthContext";
import { DocumentProvider } from "@/context/document/DocumentContext";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { Outlet, createRootRoute } from "@tanstack/react-router";
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
@@ -13,7 +12,6 @@ export const Route = createRootRoute({
</DocumentProvider>
</AuthProvider>
<TanStackRouterDevtools />
<ReactQueryDevtools buttonPosition="bottom-right" />
</>
),
});

View File

@@ -1,11 +1,10 @@
import { useCallback } from "react";
import { useCallback, useEffect, useState } from "react";
import { createFileRoute, Link } from "@tanstack/react-router";
import { pb } from "@/lib/pocketbase";
import { SessionRow } from "@/components/documents/session/SessionRow";
import { Button } from "@headlessui/react";
import { useQueryClient, useSuspenseQuery } from "@tanstack/react-query";
import { Loader } from "@/components/Loader";
import type { Relationship } from "@/lib/types";
import type { Campaign, Relationship, Session } from "@/lib/types";
export const Route = createFileRoute(
"/_app/_authenticated/campaigns/$campaignId",
@@ -15,14 +14,15 @@ export const Route = createFileRoute(
});
function RouteComponent() {
const queryClient = useQueryClient();
const params = Route.useParams();
const {
data: { campaign, sessions },
} = useSuspenseQuery({
queryKey: ["campaign"],
queryFn: async () => {
const [loading, setLoading] = useState(true);
const [campaign, setCampaign] = useState<Campaign | null>(null);
const [sessions, setSessions] = useState<Session[]>([]);
useEffect(() => {
async function fetchData() {
setLoading(true);
const campaign = await pb
.collection("campaigns")
.getOne(params.campaignId);
@@ -31,14 +31,17 @@ function RouteComponent() {
filter: `campaign = "${params.campaignId}" && type = 'session'`,
sort: "-created",
});
return {
campaign,
sessions,
};
},
});
setSessions(sessions as Session[]);
setCampaign(campaign as Campaign);
setLoading(false);
}
fetchData();
}, [setCampaign, setSessions, setLoading]);
const createNewSession = useCallback(async () => {
if (campaign === null) {
return;
}
// Check for a previous session
const prevSession = await pb
.collection("documents")
@@ -70,10 +73,12 @@ function RouteComponent() {
});
}
}
queryClient.invalidateQueries({ queryKey: ["campaign"] });
}, [campaign]);
if (loading || campaign === null) {
return <Loader />;
}
return (
<div className="max-w-xl mx-auto py-8">
<div className="mb-2">

View File

@@ -1,9 +1,8 @@
import { DocumentPrintRow } from "@/components/documents/DocumentPrintRow";
import { SessionPrintRow } from "@/components/documents/session/SessionPrintRow";
import { Loader } from "@/components/Loader";
import { pb } from "@/lib/pocketbase";
import { RelationshipType, type Relationship, type Session } from "@/lib/types";
import { useSuspenseQuery } from "@tanstack/react-query";
import { useDocument, useDocumentCache } from "@/context/document/hooks";
import { RelationshipType, type DocumentId, type Session } from "@/lib/types";
import { createFileRoute } from "@tanstack/react-router";
import _ from "lodash";
@@ -16,32 +15,28 @@ export const Route = createFileRoute(
function RouteComponent() {
const params = Route.useParams();
const {
data: { session, relationships },
} = useSuspenseQuery({
queryKey: ["session", "relationships"],
queryFn: async () => {
const session = await pb
.collection("documents")
.getOne(params.documentId);
const relationships: Relationship[] = await pb
.collection("relationships")
.getFullList({
filter: `primary = "${params.documentId}"`,
expand: "secondary",
});
console.log("Fetched data: ", relationships);
return {
session: session as Session,
relationships: _.mapValues(
_.groupBy(relationships, (r) => r.type),
(rs: Relationship[]) => rs.flatMap((r) => r.expand?.secondary),
),
};
},
});
console.log("Parsed data: ", relationships);
const { cache } = useDocumentCache();
const { docResult } = useDocument(params.documentId as DocumentId);
if (docResult.type !== "ready") {
return <Loader />;
}
const session = docResult.value.doc as Session;
const relationships = _.mapValues(
docResult.value.relationships,
(relResult) => {
if (relResult.type != "ready") {
return [];
}
return relResult.value.secondary
.map((id) => cache.documents[id])
.flatMap((docResult) =>
docResult.type === "ready" ? [docResult.value.doc] : [],
);
},
);
return (
<div className="fill-w py-8 columns-2 gap-8 text-sm">