From c104277964e6c8e534951596a605f3293be86311 Mon Sep 17 00:00:00 2001 From: andwati Date: Mon, 15 Jun 2026 11:46:34 +0300 Subject: [PATCH] final --- orders-frontend/src/hooks/useAuth.tsx | 47 +++++++++++++++++++++++++-- orders-frontend/src/routes/cart.tsx | 10 ++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/orders-frontend/src/hooks/useAuth.tsx b/orders-frontend/src/hooks/useAuth.tsx index ce53f4c..4e0f547 100644 --- a/orders-frontend/src/hooks/useAuth.tsx +++ b/orders-frontend/src/hooks/useAuth.tsx @@ -1,6 +1,6 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { createContext, useContext, useState } from "react"; -import { login, logout, register } from "#/api/auth"; +import { createContext, useContext, useEffect, useState } from "react"; +import { getCurrentUser, login, logout, register } from "#/api/auth"; import type { AuthUser, LoginRequest, RegisterRequest } from "#/types/auth"; type AuthContextValue = { @@ -21,6 +21,47 @@ export const authQueryKeys = { export function AuthProvider({ children }: { children: React.ReactNode }) { const queryClient = useQueryClient(); const [user, setUser] = useState(() => readStoredUser()); + const [isLoading, setIsLoading] = useState(() => readStoredUser() !== null); + const userId = user?.id; + + useEffect(() => { + let cancelled = false; + + if (!userId) { + setIsLoading(false); + return; + } + + setIsLoading(true); + getCurrentUser() + .then((currentUser) => { + if (cancelled) { + return; + } + + persistUser(currentUser); + setUser(currentUser); + queryClient.setQueryData(authQueryKeys.me, currentUser); + }) + .catch(() => { + if (cancelled) { + return; + } + + persistUser(null); + setUser(null); + queryClient.clear(); + }) + .finally(() => { + if (!cancelled) { + setIsLoading(false); + } + }); + + return () => { + cancelled = true; + }; + }, [queryClient, userId]); const loginMutation = useMutation({ mutationFn: login, @@ -60,7 +101,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { const value: AuthContextValue = { user, - isLoading: false, + isLoading, login: loginMutation.mutateAsync, register: registerMutation.mutateAsync, logout: logoutUser, diff --git a/orders-frontend/src/routes/cart.tsx b/orders-frontend/src/routes/cart.tsx index 69f3885..4e8a654 100644 --- a/orders-frontend/src/routes/cart.tsx +++ b/orders-frontend/src/routes/cart.tsx @@ -2,6 +2,7 @@ import { createFileRoute, Link, useNavigate } from "@tanstack/react-router"; import { CreditCard, ShoppingCart, Trash2 } from "lucide-react"; import { useMemo, useState } from "react"; import { toast } from "sonner"; +import { ApiError } from "#/api/client"; import { AuthDialog } from "#/components/store/AuthDialog"; import { QuantityStepper } from "#/components/store/QuantityStepper"; import { SiteHeader } from "#/components/store/SiteHeader"; @@ -129,6 +130,15 @@ function CartPage() { }); await navigate({ to: "/orders" }); } catch (error) { + if (error instanceof ApiError && error.status === 403) { + await logout(); + setAuthMode("login"); + toast.error("Sign in again", { + description: "Your session expired before checkout.", + }); + return; + } + toast.error("Checkout failed", { description: error instanceof Error