add cart no token replace auth login
This commit is contained in:
@@ -7,19 +7,13 @@ import { Card } from '@/shared/ui/card';
|
||||
import { Skeleton } from '@/shared/ui/skeleton';
|
||||
import { ProductCard } from '@/widgets/categories/ui/product-card';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { AxiosError } from 'axios';
|
||||
import { Heart } from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export default function Favourite() {
|
||||
const router = useRouter();
|
||||
const t = useTranslations();
|
||||
const {
|
||||
data: favourite,
|
||||
isLoading,
|
||||
error,
|
||||
} = useQuery({
|
||||
const { data: favourite, isLoading } = useQuery({
|
||||
queryKey: ['favourite_product'],
|
||||
queryFn: () => product_api.favouuriteProduct(),
|
||||
select(data) {
|
||||
@@ -27,14 +21,6 @@ export default function Favourite() {
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if ((error as AxiosError)?.status === 403) {
|
||||
router.replace('/auth');
|
||||
} else if ((error as AxiosError)?.status === 401) {
|
||||
router.replace('/auth');
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
if (favourite && favourite.results.length === 0) {
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
import { cart_api } from '@/features/cart/lib/api';
|
||||
import { product_api } from '@/shared/config/api/product/api';
|
||||
import { BASE_URL } from '@/shared/config/api/URLs';
|
||||
import { useRouter } from '@/shared/config/i18n/navigation';
|
||||
import { useCartId } from '@/shared/hooks/cartId';
|
||||
import formatPrice from '@/shared/lib/formatPrice';
|
||||
import { cn } from '@/shared/lib/utils';
|
||||
import { Input } from '@/shared/ui/input';
|
||||
import { Skeleton } from '@/shared/ui/skeleton';
|
||||
import { userStore } from '@/widgets/welcome/lib/hook';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { AxiosError } from 'axios';
|
||||
import { Heart, Minus, Plus, Shield, ShoppingCart, Truck } from 'lucide-react';
|
||||
@@ -22,6 +24,8 @@ const ProductDetail = () => {
|
||||
const { product } = useParams<{ product: string }>();
|
||||
const queryClient = useQueryClient();
|
||||
const { cart_id } = useCartId();
|
||||
const { user } = userStore();
|
||||
const router = useRouter();
|
||||
|
||||
const [quantity, setQuantity] = useState<number | string>(1);
|
||||
|
||||
@@ -46,6 +50,23 @@ const ProductDetail = () => {
|
||||
enabled: !!cart_id,
|
||||
});
|
||||
|
||||
const favouriteMutation = useMutation({
|
||||
mutationFn: (productId: string) => product_api.favourite(productId),
|
||||
|
||||
onSuccess: () => {
|
||||
queryClient.refetchQueries({ queryKey: ['product_detail'] });
|
||||
queryClient.refetchQueries({ queryKey: ['favourite_product'] });
|
||||
},
|
||||
|
||||
onError: (err: AxiosError) => {
|
||||
const detail = (err.response?.data as { detail?: string })?.detail;
|
||||
toast.error(detail || err.message, {
|
||||
richColors: true,
|
||||
position: 'top-center',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const measurement = data?.meansurement?.name?.toLowerCase() || '';
|
||||
const isGram = measurement === 'gr';
|
||||
|
||||
@@ -164,7 +185,10 @@ const ProductDetail = () => {
|
||||
|
||||
/* ---------------- HANDLERS ---------------- */
|
||||
const handleAddToCart = () => {
|
||||
// ✅ Debounce-ni bekor qil - double request oldini olish
|
||||
if (user == null) {
|
||||
router.push('/auth');
|
||||
return;
|
||||
}
|
||||
if (debounceRef.current) clearTimeout(debounceRef.current);
|
||||
isManualInputRef.current = false;
|
||||
|
||||
@@ -323,9 +347,18 @@ const ProductDetail = () => {
|
||||
|
||||
<button
|
||||
className={cn(
|
||||
'p-3 rounded-lg border',
|
||||
'p-3 rounded-lg border cursor-pointer',
|
||||
data?.liked ? 'border-red-500 bg-red-50' : 'border-gray-300',
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (user == null) {
|
||||
router.push('/auth');
|
||||
return;
|
||||
} else {
|
||||
favouriteMutation.mutate(String(data?.id));
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Heart
|
||||
className={data?.liked ? 'fill-red-500 text-red-500' : ''}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { removeRefToken, removeToken } from '@/shared/lib/token';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/shared/ui/avatar';
|
||||
import { Button } from '@/shared/ui/button';
|
||||
import { banner_api } from '@/widgets/welcome/lib/api';
|
||||
import { userStore } from '@/widgets/welcome/lib/hook';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { Headset, Home, LogOut } from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
@@ -17,6 +18,7 @@ const Profile = () => {
|
||||
const router = useRouter();
|
||||
const t = useTranslations();
|
||||
const queryClient = useQueryClient();
|
||||
const { setUser } = userStore();
|
||||
|
||||
const { data: me, isError } = useQuery({
|
||||
queryKey: ['get_me'],
|
||||
@@ -119,6 +121,7 @@ const Profile = () => {
|
||||
removeToken();
|
||||
removeRefToken();
|
||||
setCartId(null);
|
||||
setUser(null);
|
||||
queryClient.refetchQueries();
|
||||
}}
|
||||
className="w-full justify-start gap-3 text-red-500 hover:text-red-600 hover:bg-red-50 mt-4"
|
||||
|
||||
@@ -16,6 +16,7 @@ import { Button } from '@/shared/ui/button';
|
||||
import { Card, CardContent } from '@/shared/ui/card';
|
||||
import { Input } from '@/shared/ui/input';
|
||||
import { FlyingAnimationPortal } from '@/widgets/animation/FlyingAnimationPortal';
|
||||
import { userStore } from '@/widgets/welcome/lib/hook';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { AxiosError } from 'axios';
|
||||
import { Heart, Minus, Plus } from 'lucide-react';
|
||||
@@ -41,6 +42,7 @@ export function ProductCard({
|
||||
const [animated, setAnimated] = useState(false);
|
||||
const debounceRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const imageRef = useRef<HTMLDivElement>(null);
|
||||
const { user } = userStore();
|
||||
|
||||
/** ✅ Measurement */
|
||||
const measurementName = product.meansurement?.name ?? null;
|
||||
@@ -67,7 +69,6 @@ export function ProductCard({
|
||||
|
||||
onError: (err: AxiosError) => {
|
||||
const detail = (err.response?.data as { detail?: string })?.detail;
|
||||
|
||||
toast.error(detail || err.message, {
|
||||
richColors: true,
|
||||
position: 'top-center',
|
||||
@@ -176,8 +177,9 @@ export function ProductCard({
|
||||
queryClient.refetchQueries({ queryKey: ['favourite_product'] });
|
||||
},
|
||||
|
||||
onError: () => {
|
||||
toast.error(t('Tizimga kirilmagan'), {
|
||||
onError: (err: AxiosError) => {
|
||||
const detail = (err.response?.data as { detail?: string })?.detail;
|
||||
toast.error(detail || err.message, {
|
||||
richColors: true,
|
||||
position: 'top-center',
|
||||
});
|
||||
@@ -215,7 +217,12 @@ export function ProductCard({
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
favouriteMutation.mutate(String(product.id));
|
||||
if (user == null) {
|
||||
router.push('/auth');
|
||||
return;
|
||||
} else {
|
||||
favouriteMutation.mutate(String(product.id));
|
||||
}
|
||||
}}
|
||||
className="absolute top-2 right-2 z-10 bg-white hover:bg-gray-200 rounded-full p-2 shadow"
|
||||
>
|
||||
@@ -261,11 +268,16 @@ export function ProductCard({
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
addToCart({
|
||||
product: String(product.id),
|
||||
quantity: defaultQty,
|
||||
cart: cart_id!,
|
||||
});
|
||||
|
||||
if (user) {
|
||||
addToCart({
|
||||
product: String(product.id),
|
||||
quantity: defaultQty,
|
||||
cart: cart_id!,
|
||||
});
|
||||
} else {
|
||||
router.push('/auth');
|
||||
}
|
||||
}}
|
||||
className="w-full bg-white border border-slate-300 text-slate-700"
|
||||
>
|
||||
|
||||
@@ -453,7 +453,14 @@ const Navbar = () => {
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
className="h-10 max-lg:hidden cursor-pointer border border-slate-200"
|
||||
onClick={() => router.push('/favourite')}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (token) {
|
||||
router.push('/favourite');
|
||||
return;
|
||||
}
|
||||
router.push('/auth');
|
||||
}}
|
||||
aria-label="my favouurite product"
|
||||
>
|
||||
<Heart className="size-4 text-foreground" />
|
||||
@@ -461,7 +468,14 @@ const Navbar = () => {
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
id="cart-icon"
|
||||
onClick={() => router.push('/cart')}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (token) {
|
||||
router.push('/cart');
|
||||
return;
|
||||
}
|
||||
router.push('/auth');
|
||||
}}
|
||||
className="h-10 relative max-lg:hidden cursor-pointer border border-slate-200"
|
||||
>
|
||||
<ShoppingCart className="size-4 text-foreground" />
|
||||
|
||||
@@ -6,10 +6,10 @@ type State = {
|
||||
};
|
||||
|
||||
type Actions = {
|
||||
setUser: (qty: UserRes) => void;
|
||||
setUser: (qty: UserRes | null) => void;
|
||||
};
|
||||
|
||||
export const userStore = create<State & Actions>((set) => ({
|
||||
user: null,
|
||||
setUser: (user: UserRes) => set(() => ({ user })),
|
||||
setUser: (user: UserRes | null) => set(() => ({ user })),
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user