From 2b46d525f2c16ff4aed5ed18c6c0fcc6853c63f9 Mon Sep 17 00:00:00 2001 From: Jelaletdin12 Date: Tue, 23 Dec 2025 13:32:57 +0500 Subject: [PATCH] fixed some bugs --- app/[locale]/cart/page.tsx | 41 +++- app/[locale]/category/[slug]/page.tsx | 53 +++-- app/[locale]/collections/[slug]/page.tsx | 65 +++-- app/[locale]/favorites/page.tsx | 35 ++- components/ErrorPage/index.tsx | 128 ++++++++++ components/PageLoader/PreLoader.tsx | 19 +- features/cart/components/CartItemCard.tsx | 9 +- features/cart/components/CartItemSkeleton.tsx | 57 +++-- .../cart/components/OrderSummarySkeleton.tsx | 81 +++++++ .../category/components/CategoryFilters.tsx | 6 +- .../components/CategoryPageClient.tsx | 176 ++++++++++---- .../category/components/CategorySkeleton.tsx | 30 +-- .../components/CollectionFilters.tsx | 2 +- .../components/CollectionPageClient.tsx | 224 ++++++++++++++---- .../components/CollectionProductsGrid.tsx | 28 ++- features/favorites/hooks/useFavorites.ts | 15 +- features/home/components/CategoryGrid.tsx | 9 +- features/home/components/HomePage.tsx | 24 +- features/home/components/ProductCard.tsx | 9 +- features/home/components/ProductGrid.tsx | 27 ++- features/orders/components/OrderPage.tsx | 69 ++++-- .../components/ProductPurchaseCard.tsx | 4 +- features/products/components/ReviewModal.tsx | 4 +- lib/types/api.ts | 2 + public/jb.webp | Bin 30820 -> 0 bytes public/jbl.png | Bin 118466 -> 0 bytes public/jbl3.webp | Bin 86888 -> 0 bytes public/jbll.png | Bin 178092 -> 0 bytes public/temp1.jpg | Bin 95454 -> 0 bytes public/temp2.jpg | Bin 123484 -> 0 bytes 30 files changed, 857 insertions(+), 260 deletions(-) create mode 100644 components/ErrorPage/index.tsx create mode 100644 features/cart/components/OrderSummarySkeleton.tsx delete mode 100644 public/jb.webp delete mode 100644 public/jbl.png delete mode 100644 public/jbl3.webp delete mode 100644 public/jbll.png delete mode 100644 public/temp1.jpg delete mode 100644 public/temp2.jpg diff --git a/app/[locale]/cart/page.tsx b/app/[locale]/cart/page.tsx index e8d67f3..42965f2 100644 --- a/app/[locale]/cart/page.tsx +++ b/app/[locale]/cart/page.tsx @@ -3,7 +3,9 @@ import { useState, useEffect, useMemo } from "react"; import { Card } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; import CartItemCard from "../../../features/cart/components/CartItemCard"; +import CartItemSkeleton from "../../../features/cart/components/CartItemSkeleton"; import OrderSummary from "../../../features/cart/components/OrderSummary"; +import OrderSummarySkeleton from "../../../features/cart/components/OrderSummarySkeleton"; import { useCart, useCreateOrder, @@ -14,6 +16,7 @@ import { useTranslations } from "next-intl"; import { useRouter } from "next/navigation"; import type { DeliveryType, PaymentType } from "@/lib/types/api"; import EmptyCart from "@/features/cart/components/EmptyCart"; +import ErrorPage from "@/components/ErrorPage"; export default function CartPage() { const [isClient, setIsClient] = useState(false); @@ -29,12 +32,14 @@ export default function CartPage() { const router = useRouter(); const t = useTranslations(); - const { data: cartResponse, isLoading, isError } = useCart(); - const { data: provinces = [] } = useRegions(); - const { data: paymentTypes = [] } = usePaymentTypes(); + const { data: cartResponse, isLoading: cartLoading, isError } = useCart(); + const { data: provinces = [], isLoading: provincesLoading } = useRegions(); + const { data: paymentTypes = [], isLoading: paymentTypesLoading } = + usePaymentTypes(); const { mutate: createOrder, isPending: isCreatingOrder } = useCreateOrder(); const cartItems = cartResponse?.data || []; + const isLoading = cartLoading || provincesLoading || paymentTypesLoading; useEffect(() => { setIsClient(true); @@ -120,12 +125,38 @@ export default function CartPage() { if (!isClient) return null; - if (isError || cartItems.length === 0) { + if (isLoading) { + return ( +
+

+ {t("cart")} +

+ +
+
+ +
+ {Array.from({ length: 3 }).map((_, i) => ( + + ))} +
+
+
+ +
+
+ ); + } + + if (isError ) { + return ; + } + if (cartItems.length === 0) { return ; } return ( -
+

{t("cart")}

diff --git a/app/[locale]/category/[slug]/page.tsx b/app/[locale]/category/[slug]/page.tsx index 3f3abf4..ce96469 100644 --- a/app/[locale]/category/[slug]/page.tsx +++ b/app/[locale]/category/[slug]/page.tsx @@ -1,35 +1,52 @@ -import type { Metadata } from "next" +import type { Metadata } from "next"; type Props = { - params: Promise<{ locale: string; slug: string }> -} + params: Promise<{ locale: string; slug: string }>; +}; -export const revalidate = 600 // ISR: Revalidate every 10 minutes +export const revalidate = 600; // ISR: Revalidate every 10 minutes + +const CATEGORY_META = { + tm: { + suffix: " | Post shop", + description: "Kategoriýa boýunça harytlary gözläň", + ogLocale: "tk_TM", + }, + ru: { + suffix: " | Post shop", + description: "Просмотр товаров в данной категории", + ogLocale: "ru_RU", + }, +} as const; export async function generateMetadata({ params }: Props): Promise { - const { locale, slug } = await params + const { locale, slug } = await params; + + const meta = + CATEGORY_META[locale as keyof typeof CATEGORY_META] ?? CATEGORY_META.ru; return { - title: `${slug.charAt(0).toUpperCase() + slug.slice(1)} | E-Commerce`, - description: `Browse ${slug} products in our store`, + title: `${slug}${meta.suffix}`, + description: meta.description, openGraph: { - locale, - type: "website", - title: `${slug.charAt(0).toUpperCase() + slug.slice(1)} | E-Commerce`, - description: `Browse ${slug} products in our store`, + locale: meta.ogLocale, + title: `${slug}${meta.suffix}`, + description: meta.description, }, - } + }; } export async function generateStaticParams() { - const categories = ["electronics", "clothing", "home-garden"] - return categories.map((slug) => ({ slug })) + const categories = ["electronics", "clothing", "home-garden"]; + return categories.map((slug) => ({ slug })); } export default async function CategoryPage(props: Props) { - const params = await props.params - const { slug } = params + const params = await props.params; + const { slug } = params; - const CategoryPageClient = (await import("../../../../features/category/components/CategoryPageClient")).default - return + const CategoryPageClient = ( + await import("../../../../features/category/components/CategoryPageClient") + ).default; + return ; } diff --git a/app/[locale]/collections/[slug]/page.tsx b/app/[locale]/collections/[slug]/page.tsx index 845351c..309e4f8 100644 --- a/app/[locale]/collections/[slug]/page.tsx +++ b/app/[locale]/collections/[slug]/page.tsx @@ -1,37 +1,64 @@ -import type { Metadata } from "next" +import type { Metadata } from "next"; type Props = { - params: Promise<{ locale: string; slug: string }> + params: Promise<{ locale: string; slug: string }>; +}; + +export const revalidate = 600; // ISR: 10 minutes + +const META = { + tm: { + titleSuffix: " | Post shop", + description: (name: string) => `${name} kolleksiýasyndaky harytlary gözläň`, + ogLocale: "tk_TM", + }, + ru: { + titleSuffix: " | Post shop", + description: (name: string) => `Просмотр товаров из коллекции «${name}»`, + ogLocale: "ru_RU", + }, +} as const; + +function formatSlug(slug: string) { + return slug + .split("-") + .map((w) => w.charAt(0).toUpperCase() + w.slice(1)) + .join(" "); } -export const revalidate = 600 // ISR: Revalidate every 10 minutes - export async function generateMetadata({ params }: Props): Promise { - const { locale, slug } = await params + const { locale, slug } = await params; + + const meta = META[locale as keyof typeof META] ?? META.ru; + const collectionName = formatSlug(slug); + const title = `${collectionName}${meta.titleSuffix}`; + const description = meta.description(collectionName); return { - title: `${slug.charAt(0).toUpperCase() + slug.slice(1)} | E-Commerce`, - description: `Browse ${slug} collection products in our store`, + title, + description, openGraph: { - locale, type: "website", - title: `${slug.charAt(0).toUpperCase() + slug.slice(1)} | E-Commerce`, - description: `Browse ${slug} collection products in our store`, + locale: meta.ogLocale, + title, + description, }, - } + }; } export async function generateStaticParams() { - const collections = ["new-arrivals", "best-sellers", "featured"] - return collections.map((slug) => ({ slug })) + const collections = ["new-arrivals", "best-sellers", "featured"]; + return collections.map((slug) => ({ slug })); } export default async function CollectionPage(props: Props) { - const params = await props.params + const params = await props.params; const CollectionPageClient = ( - await import("../../../../features/collections/components/CollectionPageClient") - ).default - - return -} \ No newline at end of file + await import( + "../../../../features/collections/components/CollectionPageClient" + ) + ).default; + + return ; +} diff --git a/app/[locale]/favorites/page.tsx b/app/[locale]/favorites/page.tsx index 989c90c..8ab3cf2 100644 --- a/app/[locale]/favorites/page.tsx +++ b/app/[locale]/favorites/page.tsx @@ -6,33 +6,46 @@ import { useTranslations } from "next-intl"; import ProductCard from "@/features/home/components/ProductCard"; import type { Favorite } from "@/lib/types/api"; import EmptyFavorites from "@/features/favorites/components/EmptyFavorites"; +import ErrorPage from "@/components/ErrorPage"; export default function FavoritesPage() { const t = useTranslations(); const { data: favorites, isLoading, isError } = useFavorites(); if (isLoading) { return ( -
-

{t("favorite_products")}

-
+
+

+ {t("favorite_products")} +

+
{Array.from({ length: 10 }).map((_, i) => ( - +
+ + + +
))}
); } - if (isError || !favorites || favorites.length === 0) { - return ( - - ); + if (isError) { + return ; + } + + if (!favorites || favorites.length === 0) { + return ; } return ( -
-

{t("favorite_products")}

+
+

+ {t("favorite_products")} +

{favorites.map((favorite: Favorite) => { const product = favorite.product; diff --git a/components/ErrorPage/index.tsx b/components/ErrorPage/index.tsx new file mode 100644 index 0000000..ab9bc8f --- /dev/null +++ b/components/ErrorPage/index.tsx @@ -0,0 +1,128 @@ +"use client"; + +import React, { useEffect, useState } from "react"; + +// Google Fonts'u içe aktarmak için bileşen dışına ekliyoruz +const fontImport = ` + @import url('https://fonts.googleapis.com/css?family=Encode+Sans+Semi+Condensed:100,200,300,400'); + + @keyframes clockwise { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } + } + @keyframes anticlockwise { + 0% { transform: rotate(360deg); } + 100% { transform: rotate(0deg); } + } + @keyframes clockwiseError { + 0% { transform: rotate(0deg); } + 20% { transform: rotate(30deg); } + 40% { transform: rotate(25deg); } + 60% { transform: rotate(30deg); } + 100% { transform: rotate(0deg); } + } + @keyframes anticlockwiseError { + 0% { transform: rotate(0deg); } + 20% { transform: rotate(-30deg); } + 40% { transform: rotate(-25deg); } + 60% { transform: rotate(-30deg); } + 100% { transform: rotate(0deg); } + } + @keyframes anticlockwiseErrorStop { + 0% { transform: rotate(0deg); } + 20% { transform: rotate(-30deg); } + 60% { transform: rotate(-30deg); } + 100% { transform: rotate(0deg); } + } +`; + +export default function ErrorPage() { + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + const timer = setTimeout(() => setIsLoading(false), 1000); + return () => clearTimeout(timer); + }, []); + + return ( +
+ {/* CSS Animasyonlarını buraya gömüyoruz */} +