207 lines
7.5 KiB
TypeScript
207 lines
7.5 KiB
TypeScript
import React from "react";
|
||
import basket from "../assets/icons/cart/basket.svg";
|
||
import paper from "../assets/icons/profile/orders/paper.svg";
|
||
import location from "../assets/icons/profile/location/location.svg";
|
||
import messageBox from "../assets/icons/profile/threads/messageBox.svg";
|
||
import { Button } from "./ui/button";
|
||
import { RefreshCw } from "lucide-react";
|
||
import { Skeleton } from "./ui/skeleton";
|
||
import { useNavigate } from "@remix-run/react";
|
||
import { safeGoBack } from "~/utils/helpers";
|
||
|
||
export default function UiProvider({
|
||
children,
|
||
isLoading,
|
||
isError,
|
||
isEmpty,
|
||
onRetry,
|
||
type,
|
||
}: {
|
||
children: React.ReactNode;
|
||
isLoading: boolean;
|
||
isError: boolean;
|
||
isEmpty: boolean;
|
||
onRetry?: () => void;
|
||
type:
|
||
| "cart"
|
||
| "following"
|
||
| "location"
|
||
| "order"
|
||
| "product"
|
||
| "threads"
|
||
| "seller"
|
||
| "wallet"
|
||
| "locationEdit";
|
||
}) {
|
||
return (
|
||
<>
|
||
{isLoading ? (
|
||
<LoadingState type={type} />
|
||
) : isError ? (
|
||
<ErrorState onRetry={onRetry} />
|
||
) : isEmpty ? (
|
||
<EmptyState type={type} />
|
||
) : (
|
||
children
|
||
)}
|
||
</>
|
||
);
|
||
}
|
||
|
||
const LoadingState = ({ type }: { type: string }) => {
|
||
if (type === "following")
|
||
return (
|
||
<div className="flex flex-col gap-4 w-full p-4">
|
||
{[...Array(3)].map((_, index) => (
|
||
<Skeleton key={index} className="w-full h-24 rounded-lg" />
|
||
))}
|
||
</div>
|
||
);
|
||
if (type === "location")
|
||
return (
|
||
<div className="flex items-center justify-center w-full py-6">
|
||
<div className="relative w-12 h-12">
|
||
<div className="absolute top-0 left-0 w-full h-full border-4 border-t-primary border-r-transparent border-b-transparent border-l-transparent rounded-full animate-spin"></div>
|
||
<div
|
||
className="absolute top-1 left-1 w-10 h-10 border-4 border-t-transparent border-r-primary border-b-transparent border-l-transparent rounded-full animate-spin"
|
||
style={{ animationDirection: "reverse", animationDuration: "0.8s" }}
|
||
></div>
|
||
<div
|
||
className="absolute top-2 left-2 w-8 h-8 border-4 border-t-transparent border-r-transparent border-b-primary border-l-transparent rounded-full animate-spin"
|
||
style={{ animationDuration: "1.2s" }}
|
||
></div>
|
||
</div>
|
||
</div>
|
||
);
|
||
if (type === "threads")
|
||
return (
|
||
<div className="flex flex-col gap-4 w-full">
|
||
{[...Array(3)].map((_, index) => (
|
||
<div
|
||
key={index}
|
||
className="w-full h-[80px] flex items-center px-4 gap-4"
|
||
>
|
||
<Skeleton className="w-[50px] h-[50px] rounded-full shrink-0" />
|
||
<div className="flex flex-col gap-2 w-full">
|
||
<Skeleton className="w-20 h-4 rounded-lg" />
|
||
<Skeleton className="w-40 h-4 rounded-lg" />
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
);
|
||
if (type === "wallet")
|
||
return (
|
||
<div className="flex items-center justify-center w-full py-6">
|
||
<div className="relative w-12 h-12">
|
||
<div className="absolute top-0 left-0 w-full h-full border-4 border-t-primary border-r-transparent border-b-transparent border-l-transparent rounded-full animate-spin"></div>
|
||
<div
|
||
className="absolute top-1 left-1 w-10 h-10 border-4 border-t-transparent border-r-primary border-b-transparent border-l-transparent rounded-full animate-spin"
|
||
style={{ animationDirection: "reverse", animationDuration: "0.8s" }}
|
||
></div>
|
||
<div
|
||
className="absolute top-2 left-2 w-8 h-8 border-4 border-t-transparent border-r-transparent border-b-primary border-l-transparent rounded-full animate-spin"
|
||
style={{ animationDuration: "1.2s" }}
|
||
></div>
|
||
</div>
|
||
</div>
|
||
);
|
||
return (
|
||
<div className="flex justify-center py-12">
|
||
<p className="text-B14">در حال بارگذاری...</p>
|
||
</div>
|
||
);
|
||
};
|
||
export const ErrorState = ({ onRetry }: { onRetry?: () => void }) => {
|
||
return (
|
||
<div className="flex justify-center items-center flex-col gap-2 py-12">
|
||
<p className="text-B16 font-bold">مشکلی در دریافت اطلاعات پیش آمده است</p>
|
||
{onRetry && (
|
||
<Button variant="dark" size="lg" onClick={onRetry}>
|
||
تلاش مجدد
|
||
<RefreshCw className="w-4 h-4" />
|
||
</Button>
|
||
)}
|
||
</div>
|
||
);
|
||
};
|
||
export const EmptyState = ({
|
||
type,
|
||
mondrianImage,
|
||
mondrianTitle,
|
||
mondrianDescription,
|
||
}: {
|
||
type: string;
|
||
mondrianImage?: React.ReactNode;
|
||
mondrianTitle?: string;
|
||
mondrianDescription?: string;
|
||
}) => {
|
||
const navigate = useNavigate();
|
||
return (
|
||
<>
|
||
{type === "cart" && (
|
||
<div className="flex w-full mt-[200px] flex-col gap-2 items-center justify-center px-4">
|
||
<img alt="cartBanner" src={basket} className="w-12 h-12" />
|
||
<p className="text-R16 text-BLACK2">سبد خرید شما خالی است</p>
|
||
<p className="text-R12 text-GRAY">
|
||
در سبد خرید، جای انتخابهای خاص شما خالیست.
|
||
</p>
|
||
</div>
|
||
)}
|
||
{type === "following" && (
|
||
<div className="flex w-full mt-[200px] flex-col gap-2 items-center justify-center">
|
||
<img alt="cartBanner" src={paper} className="w-12 h-12" />
|
||
<p className="text-R16 text-BLACK2">فروشگاهی دنبال نشده است.</p>
|
||
<p className="text-R12 text-GRAY">
|
||
تمام فروشگاههایی که دنبال میکنید در این قسمت قابل مشاهده است.
|
||
</p>
|
||
</div>
|
||
)}
|
||
{type === "location" && (
|
||
<div className="flex flex-col gap-2 items-center mt-[200px]">
|
||
<img alt="" src={location} className="w-12 h-12" />
|
||
<p className="text-R16 text-BLACK2">هنوز آدرسی ثبت نشده است</p>
|
||
<p className="text-R12 text-GRAY">اولین آدرس خود را ثبت کنید</p>
|
||
</div>
|
||
)}
|
||
{type === "locationEdit" && (
|
||
<div className="h-[500px] w-full bg-WHITE3 flex items-center justify-center flex-col gap-2 mt-[200px]">
|
||
<p className="text-lg font-medium">آدرس مورد نظر یافت نشد</p>
|
||
<Button
|
||
onClick={() => safeGoBack(navigate)}
|
||
size={"sm"}
|
||
variant="primary"
|
||
>
|
||
بازگشت
|
||
</Button>
|
||
</div>
|
||
)}
|
||
{type === "threads" && (
|
||
<div className="flex w-full mt-[200px] flex-col gap-2 items-center justify-center">
|
||
<img alt="messageBox" src={messageBox} className="w-12 h-12" />
|
||
<p className="text-R16 text-BLACK2">لیست پیامها خالی است.</p>
|
||
<p className="text-R12 text-GRAY">
|
||
هنوز پیامی دریافت یا ارسال نکردهاید
|
||
</p>
|
||
</div>
|
||
)}
|
||
{type === "orders" && (
|
||
<div className="flex w-full mt-[200px] flex-col gap-2 items-center justify-center">
|
||
<img alt="cartBanner" src={basket} className="w-12 h-12" />
|
||
<p className="text-R16 text-BLACK2">هنوز سفارشی ثبت نشده است</p>
|
||
<p className="text-R12 text-GRAY">
|
||
از محصولات دیدن کنید و سفارش خود را ثبت کنید.
|
||
</p>
|
||
</div>
|
||
)}
|
||
{type === "mondrian" && (
|
||
<div className="flex w-full mt-[200px] flex-col gap-2 items-center justify-center">
|
||
{mondrianImage}
|
||
<p className="text-R16 text-BLACK2">{mondrianTitle}</p>
|
||
<p className="text-R12 text-GRAY">{mondrianDescription}</p>
|
||
</div>
|
||
)}
|
||
</>
|
||
);
|
||
};
|