feat : dynamic profile api and add logout btn
This commit is contained in:
5
src/hooks/useQueryParams.ts
Normal file
5
src/hooks/useQueryParams.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { useLocation } from "react-router-dom";
|
||||||
|
|
||||||
|
export const useQueryParams = () => {
|
||||||
|
return new URLSearchParams(useLocation().search);
|
||||||
|
};
|
||||||
@@ -1,12 +1,94 @@
|
|||||||
import ProfileDetails from "./section/ProfileDetails";
|
import ProfileDetails from "./section/ProfileDetails";
|
||||||
import ProductConfigList from "./section/ProductConfigList";
|
import ProductConfigList from "./section/ProductConfigList";
|
||||||
|
import { useQueryParams } from "../../hooks/useQueryParams";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
|
import useAxios from "../../hooks/useAxios";
|
||||||
|
import { AxiosError, AxiosResponse } from "axios";
|
||||||
|
import ModalPayment from "./section/components/ModalPayment";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
const Profile = () => {
|
const Profile = () => {
|
||||||
|
const query = useQueryParams();
|
||||||
|
const axios = useAxios();
|
||||||
|
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||||
|
const [isPayment, setIsPayment] = useState<boolean>(false);
|
||||||
|
const [message, setMessage] = useState<string>("");
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const mutation = useMutation({
|
||||||
|
mutationKey: ["statusPayment"],
|
||||||
|
mutationFn: (values: { trackId: string }) => {
|
||||||
|
return axios.post("/home/config/confirm", values);
|
||||||
|
},
|
||||||
|
onSuccess: (data) => {
|
||||||
|
setIsOpen(true);
|
||||||
|
setIsPayment(true);
|
||||||
|
setMessage(data?.data?.result?.alert);
|
||||||
|
navigate("/profile", { replace: true });
|
||||||
|
},
|
||||||
|
onError: (err: AxiosError) => {
|
||||||
|
let errorMessage = "یک خطای غیرمنتظره رخ داد";
|
||||||
|
if (
|
||||||
|
err.response?.data &&
|
||||||
|
typeof err.response.data === "object" &&
|
||||||
|
"alert" in err.response.data
|
||||||
|
) {
|
||||||
|
errorMessage = (err.response.data as { alert: string }).alert;
|
||||||
|
}
|
||||||
|
setIsOpen(true);
|
||||||
|
setIsPayment(false);
|
||||||
|
setMessage(errorMessage);
|
||||||
|
navigate("/profile", { replace: true });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
const trackId = query.get("trackId");
|
||||||
|
|
||||||
|
if (trackId) {
|
||||||
|
toast.promise(mutation.mutateAsync({ trackId }), {
|
||||||
|
loading: "درحال تایید درگاه پرداخت...",
|
||||||
|
success: (res: AxiosResponse) => {
|
||||||
|
return `${res.data.alert}`;
|
||||||
|
},
|
||||||
|
error: (err: AxiosError) => {
|
||||||
|
let errorMessage = "یک خطای غیرمنتظره رخ داد";
|
||||||
|
if (
|
||||||
|
err.response?.data &&
|
||||||
|
typeof err.response.data === "object" &&
|
||||||
|
"alert" in err.response.data
|
||||||
|
) {
|
||||||
|
errorMessage = (err.response.data as { alert: string }).alert;
|
||||||
|
}
|
||||||
|
return errorMessage;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error("Track ID is missing or invalid.");
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const {data,isLoading,isFetching,error} = useQuery({
|
||||||
|
queryKey:["profile",mutation],
|
||||||
|
queryFn:()=>{
|
||||||
|
return axios.get('/profile');
|
||||||
|
}
|
||||||
|
})
|
||||||
return (
|
return (
|
||||||
<div className="relative h-full w-full flex flex-col gap-4">
|
<>
|
||||||
<ProfileDetails />
|
{!mutation.isPending && (
|
||||||
<ProductConfigList />
|
<ModalPayment
|
||||||
</div>
|
isOpen={isOpen}
|
||||||
|
setIsOpen={setIsOpen}
|
||||||
|
isPayment={isPayment}
|
||||||
|
message={message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div className="relative h-full w-full flex flex-col gap-4">
|
||||||
|
<ProfileDetails data={data?.data} isLoading={isLoading} isFetching={isFetching} error={error} userTitle=""/>
|
||||||
|
<ProductConfigList data={data?.data} userTitle={data?.data?.result?.user_profile?.name} isLoading={isLoading} isFetching={isFetching} error={error} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,34 @@
|
|||||||
|
import { LoaderIcon } from "react-hot-toast";
|
||||||
|
import Alert from "../../../components/alert/Alert";
|
||||||
|
import Button from "../../../components/button";
|
||||||
|
import { ProfileDetailsProps } from "../../../types/props";
|
||||||
import ConfigItem from "./components/ConfigItem";
|
import ConfigItem from "./components/ConfigItem";
|
||||||
|
import ConfigItemLoading from "./components/ConfigItemLoading";
|
||||||
import ProfileImage from "./components/ProfileImage";
|
import ProfileImage from "./components/ProfileImage";
|
||||||
|
import { Fragment } from "react/jsx-runtime";
|
||||||
|
|
||||||
const ProductConfigList = () => {
|
const ProductConfigList = ({
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
isFetching,
|
||||||
|
error,
|
||||||
|
userTitle,
|
||||||
|
}: ProfileDetailsProps) => {
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full p-5 glass flex flex-col gap-3">
|
<div className="w-full h-full p-5 glass flex flex-col gap-3">
|
||||||
<ProfileImage />
|
<ProfileImage />
|
||||||
|
<div className="w-full h-full flex justify-center items-center">
|
||||||
|
<Button extra="!py-3 max-md:!py-1 max-md:px-2 !bg-gray-800 !text-white">
|
||||||
|
{isLoading || isFetching ? (
|
||||||
|
<LoaderIcon className="m-1.5" />
|
||||||
|
) : error ? (
|
||||||
|
"error"
|
||||||
|
) : (
|
||||||
|
userTitle
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p className="max-md:text-lg text-xl font-bold text-center">
|
<p className="max-md:text-lg text-xl font-bold text-center">
|
||||||
لیست کانفیگ ها
|
لیست کانفیگ ها
|
||||||
</p>
|
</p>
|
||||||
@@ -12,21 +36,33 @@ const ProductConfigList = () => {
|
|||||||
className="w-full h-full p-3 flex flex-col gap-3
|
className="w-full h-full p-3 flex flex-col gap-3
|
||||||
justify-center items-center"
|
justify-center items-center"
|
||||||
>
|
>
|
||||||
<ConfigItem
|
{isLoading || isFetching ? (
|
||||||
configName="سرویس تست 1 روزه"
|
Array(3)
|
||||||
dateBuy="1402/2/3"
|
.fill(null)
|
||||||
isDisabled={false}
|
.map((_, i) => (
|
||||||
/>
|
<Fragment key={i}>
|
||||||
<ConfigItem
|
<ConfigItemLoading />
|
||||||
configName="سرویس مولتی 1"
|
</Fragment>
|
||||||
dateBuy="1403/2/3"
|
))
|
||||||
isDisabled={false}
|
) : error ? (
|
||||||
/>
|
<Alert type="danger" message="خطایی با این موضوع رخ داد: ">
|
||||||
<ConfigItem
|
{error.message}
|
||||||
configName="سرویس کاهش پینگ"
|
</Alert>
|
||||||
dateBuy="1402/4/3"
|
) : (
|
||||||
isDisabled={true}
|
data?.result?.configs?.map((item) => {
|
||||||
/>
|
return (
|
||||||
|
<Fragment key={item.id}>
|
||||||
|
<ConfigItem
|
||||||
|
configName={item.title}
|
||||||
|
dateBuy={item.created_at || "تاریخ نامعتبر"}
|
||||||
|
isDisabled={false}
|
||||||
|
isShowTraffic={item.show_traffic}
|
||||||
|
textCopy={item.url}
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,13 +1,27 @@
|
|||||||
import { MdEdit } from "react-icons/md";
|
import { MdLogout } from "react-icons/md";
|
||||||
import Button from "../../../components/button";
|
import Button from "../../../components/button";
|
||||||
import ModalEditProfile from "./components/ModalEditProfile";
|
import { useDispatch } from "react-redux";
|
||||||
import { useState } from "react";
|
import { setToken } from "../../../redux/slices/token";
|
||||||
|
import { AxiosError } from "axios";
|
||||||
|
import { LoaderIcon } from "react-hot-toast";
|
||||||
|
import { ProfileDetailsProps } from "../../../types/props";
|
||||||
|
|
||||||
const ProfileDetails = () => {
|
const ProfileDetails = ({
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
isFetching,
|
||||||
|
error,
|
||||||
|
}: ProfileDetailsProps) => {
|
||||||
return (
|
return (
|
||||||
<div className="relative z-[10] w-full h-32 max-md:h-20 flex flex-row-reverse justify-between glass items-center py-2 px-4">
|
<div className="relative z-[10] w-full h-32 max-md:h-20 flex flex-row-reverse justify-between glass items-center py-2 px-4">
|
||||||
<EditProfile />
|
<EditProfile />
|
||||||
<ProductDetails />
|
<ProductDetails
|
||||||
|
enable_config={data?.result?.enable_config}
|
||||||
|
disable_config={data?.result?.disable_config}
|
||||||
|
isLoading={isLoading}
|
||||||
|
isFetching={isFetching}
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -15,32 +29,67 @@ const ProfileDetails = () => {
|
|||||||
export default ProfileDetails;
|
export default ProfileDetails;
|
||||||
|
|
||||||
const EditProfile = () => {
|
const EditProfile = () => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
// const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const dispatch = useDispatch();
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full flex justify-end items-center">
|
<div className="w-full h-full flex justify-end items-center gap-2">
|
||||||
<ModalEditProfile isOpen={isOpen} setIsOpen={setIsOpen} />
|
{/* <ModalEditProfile isOpen={isOpen} setIsOpen={setIsOpen} /> */}
|
||||||
<Button
|
{/* <Button
|
||||||
extra="!py-4 max-md:!py-2 max-md:px-2"
|
extra="!py-4 max-md:!py-2 max-md:px-2"
|
||||||
onClick={() => setIsOpen(true)}
|
onClick={() => setIsOpen(true)}
|
||||||
>
|
>
|
||||||
<MdEdit className="scale-[1.4] max-md:scale-100" />
|
<MdEdit className="scale-[1.4] max-md:scale-100" />
|
||||||
|
</Button> */}
|
||||||
|
<Button
|
||||||
|
extra="!py-4 max-md:!py-2 max-md:px-2 !bg-rose-600 !text-white"
|
||||||
|
onClick={() => dispatch(setToken(""))}
|
||||||
|
>
|
||||||
|
<MdLogout className="scale-[1.4] max-md:scale-100" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ProductDetails = () => {
|
const ProductDetails = ({
|
||||||
|
enable_config,
|
||||||
|
disable_config,
|
||||||
|
isLoading,
|
||||||
|
isFetching,
|
||||||
|
error,
|
||||||
|
}: {
|
||||||
|
enable_config: number;
|
||||||
|
disable_config: number;
|
||||||
|
isLoading: boolean;
|
||||||
|
isFetching: boolean;
|
||||||
|
error: Error | AxiosError | null;
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full flex justify-start items-center">
|
<div className="w-full h-full flex justify-start items-center">
|
||||||
<div className="md:mr-4 w-auto h-auto flex flex-col max-md:text-[12px] text-lg md:gap-2">
|
<div className="md:mr-4 w-auto h-auto flex flex-col max-md:text-[12px] text-lg md:gap-2">
|
||||||
<p className="text-nowrap">
|
<div className="text-nowrap">
|
||||||
کانفیگ های فعال :{" "}
|
کانفیگ های فعال :{" "}
|
||||||
<span className="px-1 md:px-2 rounded-md bg-green-600"> 2 </span>
|
<span className="px-1 md:px-2 rounded-md bg-green-600">
|
||||||
</p>
|
{isLoading || isFetching ? (
|
||||||
<p className="text-nowrap">
|
<LoaderIcon className="inline-block" />
|
||||||
|
) : error ? (
|
||||||
|
"error"
|
||||||
|
) : (
|
||||||
|
enable_config
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="text-nowrap">
|
||||||
کانفیگ های غیر فعال :{" "}
|
کانفیگ های غیر فعال :{" "}
|
||||||
<span className="px-1 md:px-2 rounded-md bg-yellow-400"> 10 </span>
|
<span className="px-1 md:px-2 rounded-md bg-yellow-400">
|
||||||
</p>
|
{isLoading || isFetching ? (
|
||||||
|
<LoaderIcon className="inline-block" />
|
||||||
|
) : error ? (
|
||||||
|
"error"
|
||||||
|
) : (
|
||||||
|
disable_config
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,13 +5,30 @@ import ModalConfigDetails from "./ModalConfigDetails";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import Dropdown, { DropdownItem } from "../../../../components/dropdown";
|
import Dropdown, { DropdownItem } from "../../../../components/dropdown";
|
||||||
import ProgressSpace from "../../../../components/progressSpace";
|
import ProgressSpace from "../../../../components/progressSpace";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
const ConfigItem = ({ dateBuy, configName, isDisabled }: ConfigItemProps) => {
|
const ConfigItem = ({
|
||||||
|
dateBuy,
|
||||||
|
configName,
|
||||||
|
isDisabled,
|
||||||
|
isShowTraffic,
|
||||||
|
textCopy,
|
||||||
|
}: ConfigItemProps) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [isOpenDropDown, setIsOpenDropDown] = useState(false);
|
const [isOpenDropDown, setIsOpenDropDown] = useState(false);
|
||||||
|
const navigate = useNavigate();
|
||||||
const handleToggle = () => {
|
const handleToggle = () => {
|
||||||
setIsOpenDropDown(!isOpen);
|
setIsOpenDropDown(!isOpen);
|
||||||
};
|
};
|
||||||
|
const copyToClipboard = async (textToCopy: string) => {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(textToCopy);
|
||||||
|
toast.success("متن با موفقیت کپی شد!");
|
||||||
|
} catch (err) {
|
||||||
|
toast.error(`Failed to copy: , ${err}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -21,11 +38,13 @@ const ConfigItem = ({ dateBuy, configName, isDisabled }: ConfigItemProps) => {
|
|||||||
dateBuy={dateBuy}
|
dateBuy={dateBuy}
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
nameConfig={configName}
|
nameConfig={configName}
|
||||||
|
isShowTraffic={isShowTraffic}
|
||||||
|
textCopy={textCopy}
|
||||||
/>
|
/>
|
||||||
<div className="relative w-full h-full rounded-md">
|
<div className="relative w-full h-full rounded-md">
|
||||||
{isDisabled && (
|
{isDisabled && (
|
||||||
<div className="absolute inset-0 flex items-center justify-center bg-opacity-50 rounded-md backdrop-blur-sm z-10">
|
<div className="absolute inset-0 flex items-center justify-center bg-opacity-50 rounded-md backdrop-blur-sm z-10">
|
||||||
<div className="text-white font-bold p-1 bg-red-600 text-xs md:text-base rounded-md shadow-md">
|
<div className="text-white font-bold max-sm:p-[2px] p-1 bg-red-600 max-sm:text-[10px] text-xs md:text-base rounded-md shadow-md">
|
||||||
کانفیگ <span className="text-secondTheme">{configName}</span> غیر
|
کانفیگ <span className="text-secondTheme">{configName}</span> غیر
|
||||||
فعال است .{" "}
|
فعال است .{" "}
|
||||||
<Button
|
<Button
|
||||||
@@ -47,27 +66,35 @@ const ConfigItem = ({ dateBuy, configName, isDisabled }: ConfigItemProps) => {
|
|||||||
{configName}
|
{configName}
|
||||||
</li>
|
</li>
|
||||||
<div className="max-md:hidden flex flex-row-reverse gap-2 justify-end items-center">
|
<div className="max-md:hidden flex flex-row-reverse gap-2 justify-end items-center">
|
||||||
<Button extra="!m-0 !px-2 !py-1.5 flex flex-row-reverse justify-center items-center gap-1 shadow-md shadow-white">
|
<Button
|
||||||
|
onClick={() => copyToClipboard(textCopy)}
|
||||||
|
extra="!m-0 !px-2 !py-1.5 flex flex-row-reverse justify-center items-center gap-1 shadow-md shadow-white"
|
||||||
|
>
|
||||||
کپی
|
کپی
|
||||||
<IoCopy />
|
<IoCopy />
|
||||||
</Button>
|
</Button>
|
||||||
<Button extra="!m-0 !px-2 !py-1.5 shadow-md">
|
<Button
|
||||||
|
extra="!m-0 !px-2 !py-1.5 shadow-md"
|
||||||
|
onClick={() => navigate("/tutorial")}
|
||||||
|
>
|
||||||
آموزش
|
آموزش
|
||||||
</Button>
|
</Button>
|
||||||
<Dropdown isOpen={isOpenDropDown} setIsOpen={setIsOpenDropDown}>
|
{isShowTraffic && (
|
||||||
<Button
|
<Dropdown isOpen={isOpenDropDown} setIsOpen={setIsOpenDropDown}>
|
||||||
id="dropdownDefaultButton"
|
<Button
|
||||||
data-dropdown-toggle="dropdown"
|
id="dropdownDefaultButton"
|
||||||
type="button"
|
data-dropdown-toggle="dropdown"
|
||||||
onClick={handleToggle}
|
type="button"
|
||||||
extra="!m-0 !px-2 !py-1.5 shadow-md"
|
onClick={handleToggle}
|
||||||
>
|
extra="!m-0 !px-2 !py-1.5 shadow-md"
|
||||||
حجم
|
>
|
||||||
</Button>
|
حجم
|
||||||
<DropdownItem widthTailwind="w-[20rem] left-0">
|
</Button>
|
||||||
<ProgressSpace startSpace={100} endSpace={200} />
|
<DropdownItem widthTailwind="w-[20rem] left-0">
|
||||||
</DropdownItem>
|
<ProgressSpace startSpace={100} endSpace={200} />
|
||||||
</Dropdown>
|
</DropdownItem>
|
||||||
|
</Dropdown>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="md:hidden flex flex-row-reverse gap-2 justify-end items-center">
|
<div className="md:hidden flex flex-row-reverse gap-2 justify-end items-center">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
25
src/pages/profile/section/components/ConfigItemLoading.tsx
Normal file
25
src/pages/profile/section/components/ConfigItemLoading.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { Skeleton } from "@mui/material";
|
||||||
|
|
||||||
|
const ConfigItemLoading = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="relative w-full h-full rounded-md">
|
||||||
|
<div
|
||||||
|
className={`w-full h-full p-3 rounded-md text-xs md:text-base gap-2 flex justify-between items-center text-secondTheme bg-gray-900 shadow-md shadow-gray-900`}
|
||||||
|
>
|
||||||
|
<Skeleton variant="rounded" animation="wave" width={100} />
|
||||||
|
<li className="px-2 py-1 shadow-md rounded-md w-auto h-auto text-gray-900 font-bold list-none">
|
||||||
|
<Skeleton variant="rounded" animation="wave" width={100} />
|
||||||
|
</li>
|
||||||
|
<div className="max-md:hidden flex flex-row-reverse gap-2 justify-end items-center">
|
||||||
|
<Skeleton variant="rounded" animation="wave" width={100} />
|
||||||
|
</div>
|
||||||
|
<div className="md:hidden flex flex-row-reverse gap-2 justify-end items-center">
|
||||||
|
<Skeleton variant="rounded" animation="wave" width={100} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ConfigItemLoading;
|
||||||
@@ -4,6 +4,8 @@ import Button from "../../../../components/button";
|
|||||||
import { IoCopy } from "react-icons/io5";
|
import { IoCopy } from "react-icons/io5";
|
||||||
import Alert from "../../../../components/alert/Alert";
|
import Alert from "../../../../components/alert/Alert";
|
||||||
import ProgressSpace from "../../../../components/progressSpace";
|
import ProgressSpace from "../../../../components/progressSpace";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
const ModalConfigDetails = ({
|
const ModalConfigDetails = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
@@ -11,13 +13,27 @@ const ModalConfigDetails = ({
|
|||||||
isDisabled,
|
isDisabled,
|
||||||
dateBuy,
|
dateBuy,
|
||||||
nameConfig,
|
nameConfig,
|
||||||
|
isShowTraffic,
|
||||||
|
textCopy
|
||||||
}: {
|
}: {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
setIsOpen: Dispatch<SetStateAction<boolean>>;
|
setIsOpen: Dispatch<SetStateAction<boolean>>;
|
||||||
isDisabled: boolean;
|
isDisabled: boolean;
|
||||||
dateBuy: string;
|
dateBuy: string;
|
||||||
nameConfig: string;
|
nameConfig: string;
|
||||||
|
isShowTraffic: boolean;
|
||||||
|
textCopy: string;
|
||||||
}) => {
|
}) => {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const copyToClipboard = async (textToCopy: string) => {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(textToCopy);
|
||||||
|
toast.success("متن با موفقیت کپی شد!");
|
||||||
|
} catch (err) {
|
||||||
|
toast.error(`Failed to copy: , ${err}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MuiModal
|
<MuiModal
|
||||||
isOpenModal={isOpen}
|
isOpenModal={isOpen}
|
||||||
@@ -38,17 +54,17 @@ const ModalConfigDetails = ({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Button extra="!m-0 !px-2 !py-1.5 flex flex-row-reverse justify-center items-center gap-1 shadow-md shadow-white">
|
<Button onClick={() => copyToClipboard(textCopy)} extra="!m-0 !px-2 !py-1.5 flex flex-row-reverse justify-center items-center gap-1 shadow-md shadow-white">
|
||||||
کپی
|
کپی
|
||||||
<IoCopy />
|
<IoCopy />
|
||||||
</Button>
|
</Button>
|
||||||
<Button extra="!m-0 !px-2 !py-1.5 shadow-md shadow-white">
|
<Button onClick={()=> navigate('/tutorial')} extra="!m-0 !px-2 !py-1.5 shadow-md shadow-white">
|
||||||
آموزش
|
آموزش
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!isDisabled && (
|
{!isDisabled || isShowTraffic && (
|
||||||
<div className="w-full h-full">
|
<div className="w-full h-full">
|
||||||
<ProgressSpace startSpace={100} endSpace={200} />
|
<ProgressSpace startSpace={100} endSpace={200} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
50
src/pages/profile/section/components/ModalPayment.tsx
Normal file
50
src/pages/profile/section/components/ModalPayment.tsx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { Dispatch, SetStateAction } from "react";
|
||||||
|
import MuiModal from "../../../../common/modal";
|
||||||
|
import { MdError, MdVerified } from "react-icons/md";
|
||||||
|
|
||||||
|
const ModalPayment = ({
|
||||||
|
isOpen,
|
||||||
|
setIsOpen,
|
||||||
|
isPayment,
|
||||||
|
message,
|
||||||
|
}: {
|
||||||
|
isOpen: boolean;
|
||||||
|
setIsOpen: Dispatch<SetStateAction<boolean>>;
|
||||||
|
isPayment: boolean;
|
||||||
|
message: string;
|
||||||
|
}) => {
|
||||||
|
console.log(isPayment);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MuiModal isOpenModal={isOpen} setIsOpenModal={setIsOpen} title="وضعیت">
|
||||||
|
<div className="relative w-full h-full px-4 py-2">
|
||||||
|
<div className="w-full h-full flex flex-col gap-4 justify-center items-center">
|
||||||
|
{isPayment ? (
|
||||||
|
<>
|
||||||
|
{" "}
|
||||||
|
<MdVerified className="w-[6rem] h-[6rem] text-green-600" />
|
||||||
|
<p className="text-base md:text-lg text-green-600">
|
||||||
|
پرداخت موفقیت امیز بود {message}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs md:text-sm">از اعتماد شما سپاسگذاریم</p>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{" "}
|
||||||
|
<MdError className="w-[6rem] h-[6rem] text-rose-600" />
|
||||||
|
<p className="text-base md:text-lg text-rose-600">
|
||||||
|
پرداخت موفقیت امیز نبود {message}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs md:text-sm">
|
||||||
|
در صورت کسر وجه اگر تا 48 ساعت برگشت داده نشد با پشتیبانی تماس
|
||||||
|
بگیرید
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</MuiModal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ModalPayment;
|
||||||
Reference in New Issue
Block a user